Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
aaa36d3a
Commit
aaa36d3a
authored
May 27, 2016
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'asoc/topic/tas5270' into asoc-next
parents
4c1c16d9
bd023ada
Changes
8
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
905 additions
and
15 deletions
+905
-15
Documentation/devicetree/bindings/sound/tas571x.txt
Documentation/devicetree/bindings/sound/tas571x.txt
+8
-2
Documentation/devicetree/bindings/sound/tas5720.txt
Documentation/devicetree/bindings/sound/tas5720.txt
+25
-0
sound/soc/codecs/Kconfig
sound/soc/codecs/Kconfig
+9
-1
sound/soc/codecs/Makefile
sound/soc/codecs/Makefile
+2
-0
sound/soc/codecs/tas571x.c
sound/soc/codecs/tas571x.c
+129
-12
sound/soc/codecs/tas571x.h
sound/soc/codecs/tas571x.h
+22
-0
sound/soc/codecs/tas5720.c
sound/soc/codecs/tas5720.c
+620
-0
sound/soc/codecs/tas5720.h
sound/soc/codecs/tas5720.h
+90
-0
No files found.
Documentation/devicetree/bindings/sound/tas571x.txt
View file @
aaa36d3a
Texas Instruments TAS5711/TAS5717/TAS5719 stereo power amplifiers
Texas Instruments TAS5711/TAS5717/TAS5719
/TAS5721
stereo power amplifiers
The codec is controlled through an I2C interface. It also has two other
The codec is controlled through an I2C interface. It also has two other
signals that can be wired up to GPIOs: reset (strongly recommended), and
signals that can be wired up to GPIOs: reset (strongly recommended), and
...
@@ -6,7 +6,11 @@ powerdown (optional).
...
@@ -6,7 +6,11 @@ powerdown (optional).
Required properties:
Required properties:
- compatible: "ti,tas5711", "ti,tas5717", or "ti,tas5719"
- compatible: should be one of the following:
- "ti,tas5711",
- "ti,tas5717",
- "ti,tas5719",
- "ti,tas5721"
- reg: The I2C address of the device
- reg: The I2C address of the device
- #sound-dai-cells: must be equal to 0
- #sound-dai-cells: must be equal to 0
...
@@ -25,6 +29,8 @@ Optional properties:
...
@@ -25,6 +29,8 @@ Optional properties:
- PVDD_B-supply: regulator phandle for the PVDD_B supply (5711)
- PVDD_B-supply: regulator phandle for the PVDD_B supply (5711)
- PVDD_C-supply: regulator phandle for the PVDD_C supply (5711)
- PVDD_C-supply: regulator phandle for the PVDD_C supply (5711)
- PVDD_D-supply: regulator phandle for the PVDD_D supply (5711)
- PVDD_D-supply: regulator phandle for the PVDD_D supply (5711)
- DRVDD-supply: regulator phandle for the DRVDD supply (5721)
- PVDD-supply: regulator phandle for the PVDD supply (5721)
Example:
Example:
...
...
Documentation/devicetree/bindings/sound/tas5720.txt
0 → 100644
View file @
aaa36d3a
Texas Instruments TAS5720 Mono Audio amplifier
The TAS5720 serial control bus communicates through the I2C protocol only. The
serial bus is also used for periodic codec fault checking/reporting during
audio playback. For more product information please see the links below:
http://www.ti.com/product/TAS5720L
http://www.ti.com/product/TAS5720M
Required properties:
- compatible : "ti,tas5720"
- reg : I2C slave address
- dvdd-supply : phandle to a 3.3-V supply for the digital circuitry
- pvdd-supply : phandle to a supply used for the Class-D amp and the analog
Example:
tas5720: tas5720@6c {
status = "okay";
compatible = "ti,tas5720";
reg = <0x6c>;
dvdd-supply = <&vdd_3v3_reg>;
pvdd-supply = <&_supply_reg>;
};
sound/soc/codecs/Kconfig
View file @
aaa36d3a
...
@@ -127,6 +127,7 @@ config SND_SOC_ALL_CODECS
...
@@ -127,6 +127,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_TAS2552 if I2C
select SND_SOC_TAS2552 if I2C
select SND_SOC_TAS5086 if I2C
select SND_SOC_TAS5086 if I2C
select SND_SOC_TAS571X if I2C
select SND_SOC_TAS571X if I2C
select SND_SOC_TAS5720 if I2C
select SND_SOC_TFA9879 if I2C
select SND_SOC_TFA9879 if I2C
select SND_SOC_TLV320AIC23_I2C if I2C
select SND_SOC_TLV320AIC23_I2C if I2C
select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
...
@@ -753,9 +754,16 @@ config SND_SOC_TAS5086
...
@@ -753,9 +754,16 @@ config SND_SOC_TAS5086
depends on I2C
depends on I2C
config SND_SOC_TAS571X
config SND_SOC_TAS571X
tristate "Texas Instruments TAS5711/TAS5717/TAS5719 power amplifiers"
tristate "Texas Instruments TAS5711/TAS5717/TAS5719
/TAS5721
power amplifiers"
depends on I2C
depends on I2C
config SND_SOC_TAS5720
tristate "Texas Instruments TAS5720 Mono Audio amplifier"
depends on I2C
help
Enable support for Texas Instruments TAS5720L/M high-efficiency mono
Class-D audio power amplifiers.
config SND_SOC_TFA9879
config SND_SOC_TFA9879
tristate "NXP Semiconductors TFA9879 amplifier"
tristate "NXP Semiconductors TFA9879 amplifier"
depends on I2C
depends on I2C
...
...
sound/soc/codecs/Makefile
View file @
aaa36d3a
...
@@ -132,6 +132,7 @@ snd-soc-stac9766-objs := stac9766.o
...
@@ -132,6 +132,7 @@ snd-soc-stac9766-objs := stac9766.o
snd-soc-sti-sas-objs
:=
sti-sas.o
snd-soc-sti-sas-objs
:=
sti-sas.o
snd-soc-tas5086-objs
:=
tas5086.o
snd-soc-tas5086-objs
:=
tas5086.o
snd-soc-tas571x-objs
:=
tas571x.o
snd-soc-tas571x-objs
:=
tas571x.o
snd-soc-tas5720-objs
:=
tas5720.o
snd-soc-tfa9879-objs
:=
tfa9879.o
snd-soc-tfa9879-objs
:=
tfa9879.o
snd-soc-tlv320aic23-objs
:=
tlv320aic23.o
snd-soc-tlv320aic23-objs
:=
tlv320aic23.o
snd-soc-tlv320aic23-i2c-objs
:=
tlv320aic23-i2c.o
snd-soc-tlv320aic23-i2c-objs
:=
tlv320aic23-i2c.o
...
@@ -342,6 +343,7 @@ obj-$(CONFIG_SND_SOC_STI_SAS) += snd-soc-sti-sas.o
...
@@ -342,6 +343,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_TAS2552)
+=
snd-soc-tas2552.o
obj-$(CONFIG_SND_SOC_TAS5086)
+=
snd-soc-tas5086.o
obj-$(CONFIG_SND_SOC_TAS5086)
+=
snd-soc-tas5086.o
obj-$(CONFIG_SND_SOC_TAS571X)
+=
snd-soc-tas571x.o
obj-$(CONFIG_SND_SOC_TAS571X)
+=
snd-soc-tas571x.o
obj-$(CONFIG_SND_SOC_TAS5720)
+=
snd-soc-tas5720.o
obj-$(CONFIG_SND_SOC_TFA9879)
+=
snd-soc-tfa9879.o
obj-$(CONFIG_SND_SOC_TFA9879)
+=
snd-soc-tfa9879.o
obj-$(CONFIG_SND_SOC_TLV320AIC23)
+=
snd-soc-tlv320aic23.o
obj-$(CONFIG_SND_SOC_TLV320AIC23)
+=
snd-soc-tlv320aic23.o
obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C)
+=
snd-soc-tlv320aic23-i2c.o
obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C)
+=
snd-soc-tlv320aic23-i2c.o
...
...
sound/soc/codecs/tas571x.c
View file @
aaa36d3a
...
@@ -4,6 +4,9 @@
...
@@ -4,6 +4,9 @@
* Copyright (C) 2015 Google, Inc.
* Copyright (C) 2015 Google, Inc.
* Copyright (c) 2013 Daniel Mack <zonque@gmail.com>
* Copyright (c) 2013 Daniel Mack <zonque@gmail.com>
*
*
* TAS5721 support:
* Copyright (C) 2016 Petr Kulhavy, Barix AG <petr@barix.com>
*
* This program is free software; you can redistribute it and/or modify
* 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* the Free Software Foundation; either version 2 of the License, or
...
@@ -57,6 +60,10 @@ static int tas571x_register_size(struct tas571x_private *priv, unsigned int reg)
...
@@ -57,6 +60,10 @@ static int tas571x_register_size(struct tas571x_private *priv, unsigned int reg)
case
TAS571X_CH1_VOL_REG
:
case
TAS571X_CH1_VOL_REG
:
case
TAS571X_CH2_VOL_REG
:
case
TAS571X_CH2_VOL_REG
:
return
priv
->
chip
->
vol_reg_size
;
return
priv
->
chip
->
vol_reg_size
;
case
TAS571X_INPUT_MUX_REG
:
case
TAS571X_CH4_SRC_SELECT_REG
:
case
TAS571X_PWM_MUX_REG
:
return
4
;
default:
default:
return
1
;
return
1
;
}
}
...
@@ -167,6 +174,23 @@ static int tas571x_hw_params(struct snd_pcm_substream *substream,
...
@@ -167,6 +174,23 @@ static int tas571x_hw_params(struct snd_pcm_substream *substream,
TAS571X_SDI_FMT_MASK
,
val
);
TAS571X_SDI_FMT_MASK
,
val
);
}
}
static
int
tas571x_mute
(
struct
snd_soc_dai
*
dai
,
int
mute
)
{
struct
snd_soc_codec
*
codec
=
dai
->
codec
;
u8
sysctl2
;
int
ret
;
sysctl2
=
mute
?
TAS571X_SYS_CTRL_2_SDN_MASK
:
0
;
ret
=
snd_soc_update_bits
(
codec
,
TAS571X_SYS_CTRL_2_REG
,
TAS571X_SYS_CTRL_2_SDN_MASK
,
sysctl2
);
usleep_range
(
1000
,
2000
);
return
ret
;
}
static
int
tas571x_set_bias_level
(
struct
snd_soc_codec
*
codec
,
static
int
tas571x_set_bias_level
(
struct
snd_soc_codec
*
codec
,
enum
snd_soc_bias_level
level
)
enum
snd_soc_bias_level
level
)
{
{
...
@@ -214,6 +238,7 @@ static int tas571x_set_bias_level(struct snd_soc_codec *codec,
...
@@ -214,6 +238,7 @@ static int tas571x_set_bias_level(struct snd_soc_codec *codec,
static
const
struct
snd_soc_dai_ops
tas571x_dai_ops
=
{
static
const
struct
snd_soc_dai_ops
tas571x_dai_ops
=
{
.
set_fmt
=
tas571x_set_dai_fmt
,
.
set_fmt
=
tas571x_set_dai_fmt
,
.
hw_params
=
tas571x_hw_params
,
.
hw_params
=
tas571x_hw_params
,
.
digital_mute
=
tas571x_mute
,
};
};
static
const
char
*
const
tas5711_supply_names
[]
=
{
static
const
char
*
const
tas5711_supply_names
[]
=
{
...
@@ -241,6 +266,26 @@ static const struct snd_kcontrol_new tas5711_controls[] = {
...
@@ -241,6 +266,26 @@ static const struct snd_kcontrol_new tas5711_controls[] = {
1
,
1
),
1
,
1
),
};
};
static
const
struct
regmap_range
tas571x_readonly_regs_range
[]
=
{
regmap_reg_range
(
TAS571X_CLK_CTRL_REG
,
TAS571X_DEV_ID_REG
),
};
static
const
struct
regmap_range
tas571x_volatile_regs_range
[]
=
{
regmap_reg_range
(
TAS571X_CLK_CTRL_REG
,
TAS571X_ERR_STATUS_REG
),
regmap_reg_range
(
TAS571X_OSC_TRIM_REG
,
TAS571X_OSC_TRIM_REG
),
};
static
const
struct
regmap_access_table
tas571x_write_regs
=
{
.
no_ranges
=
tas571x_readonly_regs_range
,
.
n_no_ranges
=
ARRAY_SIZE
(
tas571x_readonly_regs_range
),
};
static
const
struct
regmap_access_table
tas571x_volatile_regs
=
{
.
yes_ranges
=
tas571x_volatile_regs_range
,
.
n_yes_ranges
=
ARRAY_SIZE
(
tas571x_volatile_regs_range
),
};
static
const
struct
reg_default
tas5711_reg_defaults
[]
=
{
static
const
struct
reg_default
tas5711_reg_defaults
[]
=
{
{
0x04
,
0x05
},
{
0x04
,
0x05
},
{
0x05
,
0x40
},
{
0x05
,
0x40
},
...
@@ -260,6 +305,8 @@ static const struct regmap_config tas5711_regmap_config = {
...
@@ -260,6 +305,8 @@ static const struct regmap_config tas5711_regmap_config = {
.
reg_defaults
=
tas5711_reg_defaults
,
.
reg_defaults
=
tas5711_reg_defaults
,
.
num_reg_defaults
=
ARRAY_SIZE
(
tas5711_reg_defaults
),
.
num_reg_defaults
=
ARRAY_SIZE
(
tas5711_reg_defaults
),
.
cache_type
=
REGCACHE_RBTREE
,
.
cache_type
=
REGCACHE_RBTREE
,
.
wr_table
=
&
tas571x_write_regs
,
.
volatile_table
=
&
tas571x_volatile_regs
,
};
};
static
const
struct
tas571x_chip
tas5711_chip
=
{
static
const
struct
tas571x_chip
tas5711_chip
=
{
...
@@ -314,6 +361,8 @@ static const struct regmap_config tas5717_regmap_config = {
...
@@ -314,6 +361,8 @@ static const struct regmap_config tas5717_regmap_config = {
.
reg_defaults
=
tas5717_reg_defaults
,
.
reg_defaults
=
tas5717_reg_defaults
,
.
num_reg_defaults
=
ARRAY_SIZE
(
tas5717_reg_defaults
),
.
num_reg_defaults
=
ARRAY_SIZE
(
tas5717_reg_defaults
),
.
cache_type
=
REGCACHE_RBTREE
,
.
cache_type
=
REGCACHE_RBTREE
,
.
wr_table
=
&
tas571x_write_regs
,
.
volatile_table
=
&
tas571x_volatile_regs
,
};
};
/* This entry is reused for tas5719 as the software interface is identical. */
/* This entry is reused for tas5719 as the software interface is identical. */
...
@@ -326,6 +375,77 @@ static const struct tas571x_chip tas5717_chip = {
...
@@ -326,6 +375,77 @@ static const struct tas571x_chip tas5717_chip = {
.
vol_reg_size
=
2
,
.
vol_reg_size
=
2
,
};
};
static
const
char
*
const
tas5721_supply_names
[]
=
{
"AVDD"
,
"DVDD"
,
"DRVDD"
,
"PVDD"
,
};
static
const
struct
snd_kcontrol_new
tas5721_controls
[]
=
{
SOC_SINGLE_TLV
(
"Master Volume"
,
TAS571X_MVOL_REG
,
0
,
0xff
,
1
,
tas5711_volume_tlv
),
SOC_DOUBLE_R_TLV
(
"Speaker Volume"
,
TAS571X_CH1_VOL_REG
,
TAS571X_CH2_VOL_REG
,
0
,
0xff
,
1
,
tas5711_volume_tlv
),
SOC_DOUBLE
(
"Speaker Switch"
,
TAS571X_SOFT_MUTE_REG
,
TAS571X_SOFT_MUTE_CH1_SHIFT
,
TAS571X_SOFT_MUTE_CH2_SHIFT
,
1
,
1
),
};
static
const
struct
reg_default
tas5721_reg_defaults
[]
=
{
{
TAS571X_CLK_CTRL_REG
,
0x6c
},
{
TAS571X_DEV_ID_REG
,
0x00
},
{
TAS571X_ERR_STATUS_REG
,
0x00
},
{
TAS571X_SYS_CTRL_1_REG
,
0xa0
},
{
TAS571X_SDI_REG
,
0x05
},
{
TAS571X_SYS_CTRL_2_REG
,
0x40
},
{
TAS571X_SOFT_MUTE_REG
,
0x00
},
{
TAS571X_MVOL_REG
,
0xff
},
{
TAS571X_CH1_VOL_REG
,
0x30
},
{
TAS571X_CH2_VOL_REG
,
0x30
},
{
TAS571X_CH3_VOL_REG
,
0x30
},
{
TAS571X_VOL_CFG_REG
,
0x91
},
{
TAS571X_MODULATION_LIMIT_REG
,
0x02
},
{
TAS571X_IC_DELAY_CH1_REG
,
0xac
},
{
TAS571X_IC_DELAY_CH2_REG
,
0x54
},
{
TAS571X_IC_DELAY_CH3_REG
,
0xac
},
{
TAS571X_IC_DELAY_CH4_REG
,
0x54
},
{
TAS571X_PWM_CH_SDN_GROUP_REG
,
0x30
},
{
TAS571X_START_STOP_PERIOD_REG
,
0x0f
},
{
TAS571X_OSC_TRIM_REG
,
0x82
},
{
TAS571X_BKND_ERR_REG
,
0x02
},
{
TAS571X_INPUT_MUX_REG
,
0x17772
},
{
TAS571X_CH4_SRC_SELECT_REG
,
0x4303
},
{
TAS571X_PWM_MUX_REG
,
0x1021345
},
};
static
const
struct
regmap_config
tas5721_regmap_config
=
{
.
reg_bits
=
8
,
.
val_bits
=
32
,
.
max_register
=
0xff
,
.
reg_read
=
tas571x_reg_read
,
.
reg_write
=
tas571x_reg_write
,
.
reg_defaults
=
tas5721_reg_defaults
,
.
num_reg_defaults
=
ARRAY_SIZE
(
tas5721_reg_defaults
),
.
cache_type
=
REGCACHE_RBTREE
,
.
wr_table
=
&
tas571x_write_regs
,
.
volatile_table
=
&
tas571x_volatile_regs
,
};
static
const
struct
tas571x_chip
tas5721_chip
=
{
.
supply_names
=
tas5721_supply_names
,
.
num_supply_names
=
ARRAY_SIZE
(
tas5721_supply_names
),
.
controls
=
tas5711_controls
,
.
num_controls
=
ARRAY_SIZE
(
tas5711_controls
),
.
regmap_config
=
&
tas5721_regmap_config
,
.
vol_reg_size
=
1
,
};
static
const
struct
snd_soc_dapm_widget
tas571x_dapm_widgets
[]
=
{
static
const
struct
snd_soc_dapm_widget
tas571x_dapm_widgets
[]
=
{
SND_SOC_DAPM_DAC
(
"DACL"
,
NULL
,
SND_SOC_NOPM
,
0
,
0
),
SND_SOC_DAPM_DAC
(
"DACL"
,
NULL
,
SND_SOC_NOPM
,
0
,
0
),
SND_SOC_DAPM_DAC
(
"DACR"
,
NULL
,
SND_SOC_NOPM
,
0
,
0
),
SND_SOC_DAPM_DAC
(
"DACR"
,
NULL
,
SND_SOC_NOPM
,
0
,
0
),
...
@@ -386,11 +506,10 @@ static int tas571x_i2c_probe(struct i2c_client *client,
...
@@ -386,11 +506,10 @@ static int tas571x_i2c_probe(struct i2c_client *client,
i2c_set_clientdata
(
client
,
priv
);
i2c_set_clientdata
(
client
,
priv
);
of_id
=
of_match_device
(
tas571x_of_match
,
dev
);
of_id
=
of_match_device
(
tas571x_of_match
,
dev
);
if
(
!
of_id
)
{
if
(
of_id
)
dev_err
(
dev
,
"Unknown device type
\n
"
);
return
-
EINVAL
;
}
priv
->
chip
=
of_id
->
data
;
priv
->
chip
=
of_id
->
data
;
else
priv
->
chip
=
(
void
*
)
id
->
driver_data
;
priv
->
mclk
=
devm_clk_get
(
dev
,
"mclk"
);
priv
->
mclk
=
devm_clk_get
(
dev
,
"mclk"
);
if
(
IS_ERR
(
priv
->
mclk
)
&&
PTR_ERR
(
priv
->
mclk
)
!=
-
ENOENT
)
{
if
(
IS_ERR
(
priv
->
mclk
)
&&
PTR_ERR
(
priv
->
mclk
)
!=
-
ENOENT
)
{
...
@@ -445,10 +564,6 @@ static int tas571x_i2c_probe(struct i2c_client *client,
...
@@ -445,10 +564,6 @@ static int tas571x_i2c_probe(struct i2c_client *client,
if
(
ret
)
if
(
ret
)
return
ret
;
return
ret
;
ret
=
regmap_update_bits
(
priv
->
regmap
,
TAS571X_SYS_CTRL_2_REG
,
TAS571X_SYS_CTRL_2_SDN_MASK
,
0
);
if
(
ret
)
return
ret
;
memcpy
(
&
priv
->
codec_driver
,
&
tas571x_codec
,
sizeof
(
priv
->
codec_driver
));
memcpy
(
&
priv
->
codec_driver
,
&
tas571x_codec
,
sizeof
(
priv
->
codec_driver
));
priv
->
codec_driver
.
controls
=
priv
->
chip
->
controls
;
priv
->
codec_driver
.
controls
=
priv
->
chip
->
controls
;
...
@@ -486,14 +601,16 @@ static const struct of_device_id tas571x_of_match[] = {
...
@@ -486,14 +601,16 @@ static const struct of_device_id tas571x_of_match[] = {
{
.
compatible
=
"ti,tas5711"
,
.
data
=
&
tas5711_chip
,
},
{
.
compatible
=
"ti,tas5711"
,
.
data
=
&
tas5711_chip
,
},
{
.
compatible
=
"ti,tas5717"
,
.
data
=
&
tas5717_chip
,
},
{
.
compatible
=
"ti,tas5717"
,
.
data
=
&
tas5717_chip
,
},
{
.
compatible
=
"ti,tas5719"
,
.
data
=
&
tas5717_chip
,
},
{
.
compatible
=
"ti,tas5719"
,
.
data
=
&
tas5717_chip
,
},
{
.
compatible
=
"ti,tas5721"
,
.
data
=
&
tas5721_chip
,
},
{
}
{
}
};
};
MODULE_DEVICE_TABLE
(
of
,
tas571x_of_match
);
MODULE_DEVICE_TABLE
(
of
,
tas571x_of_match
);
static
const
struct
i2c_device_id
tas571x_i2c_id
[]
=
{
static
const
struct
i2c_device_id
tas571x_i2c_id
[]
=
{
{
"tas5711"
,
0
},
{
"tas5711"
,
(
kernel_ulong_t
)
&
tas5711_chip
},
{
"tas5717"
,
0
},
{
"tas5717"
,
(
kernel_ulong_t
)
&
tas5717_chip
},
{
"tas5719"
,
0
},
{
"tas5719"
,
(
kernel_ulong_t
)
&
tas5717_chip
},
{
"tas5721"
,
(
kernel_ulong_t
)
&
tas5721_chip
},
{
}
{
}
};
};
MODULE_DEVICE_TABLE
(
i2c
,
tas571x_i2c_id
);
MODULE_DEVICE_TABLE
(
i2c
,
tas571x_i2c_id
);
...
...
sound/soc/codecs/tas571x.h
View file @
aaa36d3a
...
@@ -13,6 +13,10 @@
...
@@ -13,6 +13,10 @@
#define _TAS571X_H
#define _TAS571X_H
/* device registers */
/* device registers */
#define TAS571X_CLK_CTRL_REG 0x00
#define TAS571X_DEV_ID_REG 0x01
#define TAS571X_ERR_STATUS_REG 0x02
#define TAS571X_SYS_CTRL_1_REG 0x03
#define TAS571X_SDI_REG 0x04
#define TAS571X_SDI_REG 0x04
#define TAS571X_SDI_FMT_MASK 0x0f
#define TAS571X_SDI_FMT_MASK 0x0f
...
@@ -27,7 +31,25 @@
...
@@ -27,7 +31,25 @@
#define TAS571X_MVOL_REG 0x07
#define TAS571X_MVOL_REG 0x07
#define TAS571X_CH1_VOL_REG 0x08
#define TAS571X_CH1_VOL_REG 0x08
#define TAS571X_CH2_VOL_REG 0x09
#define TAS571X_CH2_VOL_REG 0x09
#define TAS571X_CH3_VOL_REG 0x0a
#define TAS571X_VOL_CFG_REG 0x0e
#define TAS571X_MODULATION_LIMIT_REG 0x10
#define TAS571X_IC_DELAY_CH1_REG 0x11
#define TAS571X_IC_DELAY_CH2_REG 0x12
#define TAS571X_IC_DELAY_CH3_REG 0x13
#define TAS571X_IC_DELAY_CH4_REG 0x14
#define TAS571X_PWM_CH_SDN_GROUP_REG 0x19
/* N/A on TAS5717, TAS5719 */
#define TAS571X_PWM_CH1_SDN_MASK (1<<0)
#define TAS571X_PWM_CH2_SDN_SHIFT (1<<1)
#define TAS571X_PWM_CH3_SDN_SHIFT (1<<2)
#define TAS571X_PWM_CH4_SDN_SHIFT (1<<3)
#define TAS571X_START_STOP_PERIOD_REG 0x1a
#define TAS571X_OSC_TRIM_REG 0x1b
#define TAS571X_OSC_TRIM_REG 0x1b
#define TAS571X_BKND_ERR_REG 0x1c
#define TAS571X_INPUT_MUX_REG 0x20
#define TAS571X_CH4_SRC_SELECT_REG 0x21
#define TAS571X_PWM_MUX_REG 0x25
#endif
/* _TAS571X_H */
#endif
/* _TAS571X_H */
sound/soc/codecs/tas5720.c
0 → 100644
View file @
aaa36d3a
/*
* tas5720.c - ALSA SoC Texas Instruments TAS5720 Mono Audio Amplifier
*
* Copyright (C)2015-2016 Texas Instruments Incorporated - http://www.ti.com
*
* Author: Andreas Dannenberg <dannenberg@ti.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* 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/errno.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/regulator/consumer.h>
#include <linux/delay.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
#include "tas5720.h"
/* Define how often to check (and clear) the fault status register (in ms) */
#define TAS5720_FAULT_CHECK_INTERVAL 200
static
const
char
*
const
tas5720_supply_names
[]
=
{
"dvdd"
,
/* Digital power supply. Connect to 3.3-V supply. */
"pvdd"
,
/* Class-D amp and analog power supply (connected). */
};
#define TAS5720_NUM_SUPPLIES ARRAY_SIZE(tas5720_supply_names)
struct
tas5720_data
{
struct
snd_soc_codec
*
codec
;
struct
regmap
*
regmap
;
struct
i2c_client
*
tas5720_client
;
struct
regulator_bulk_data
supplies
[
TAS5720_NUM_SUPPLIES
];
struct
delayed_work
fault_check_work
;
unsigned
int
last_fault
;
};
static
int
tas5720_hw_params
(
struct
snd_pcm_substream
*
substream
,
struct
snd_pcm_hw_params
*
params
,
struct
snd_soc_dai
*
dai
)
{
struct
snd_soc_codec
*
codec
=
dai
->
codec
;
unsigned
int
rate
=
params_rate
(
params
);
bool
ssz_ds
;
int
ret
;
switch
(
rate
)
{
case
44100
:
case
48000
:
ssz_ds
=
false
;
break
;
case
88200
:
case
96000
:
ssz_ds
=
true
;
break
;
default:
dev_err
(
codec
->
dev
,
"unsupported sample rate: %u
\n
"
,
rate
);
return
-
EINVAL
;
}
ret
=
snd_soc_update_bits
(
codec
,
TAS5720_DIGITAL_CTRL1_REG
,
TAS5720_SSZ_DS
,
ssz_ds
);
if
(
ret
<
0
)
{
dev_err
(
codec
->
dev
,
"error setting sample rate: %d
\n
"
,
ret
);
return
ret
;
}
return
0
;
}
static
int
tas5720_set_dai_fmt
(
struct
snd_soc_dai
*
dai
,
unsigned
int
fmt
)
{
struct
snd_soc_codec
*
codec
=
dai
->
codec
;
u8
serial_format
;
int
ret
;
if
((
fmt
&
SND_SOC_DAIFMT_MASTER_MASK
)
!=
SND_SOC_DAIFMT_CBS_CFS
)
{
dev_vdbg
(
codec
->
dev
,
"DAI Format master is not found
\n
"
);
return
-
EINVAL
;
}
switch
(
fmt
&
(
SND_SOC_DAIFMT_FORMAT_MASK
|
SND_SOC_DAIFMT_INV_MASK
))
{
case
(
SND_SOC_DAIFMT_I2S
|
SND_SOC_DAIFMT_NB_NF
):
/* 1st data bit occur one BCLK cycle after the frame sync */
serial_format
=
TAS5720_SAIF_I2S
;
break
;
case
(
SND_SOC_DAIFMT_DSP_A
|
SND_SOC_DAIFMT_NB_NF
):
/*
* Note that although the TAS5720 does not have a dedicated DSP
* mode it doesn't care about the LRCLK duty cycle during TDM
* operation. Therefore we can use the device's I2S mode with
* its delaying of the 1st data bit to receive DSP_A formatted
* data. See device datasheet for additional details.
*/
serial_format
=
TAS5720_SAIF_I2S
;
break
;
case
(
SND_SOC_DAIFMT_DSP_B
|
SND_SOC_DAIFMT_NB_NF
):
/*
* Similar to DSP_A, we can use the fact that the TAS5720 does
* not care about the LRCLK duty cycle during TDM to receive
* DSP_B formatted data in LEFTJ mode (no delaying of the 1st
* data bit).
*/
serial_format
=
TAS5720_SAIF_LEFTJ
;
break
;
case
(
SND_SOC_DAIFMT_LEFT_J
|
SND_SOC_DAIFMT_NB_NF
):
/* No delay after the frame sync */
serial_format
=
TAS5720_SAIF_LEFTJ
;
break
;
default:
dev_vdbg
(
codec
->
dev
,
"DAI Format is not found
\n
"
);
return
-
EINVAL
;
}
ret
=
snd_soc_update_bits
(
codec
,
TAS5720_DIGITAL_CTRL1_REG
,
TAS5720_SAIF_FORMAT_MASK
,
serial_format
);
if
(
ret
<
0
)
{
dev_err
(
codec
->
dev
,
"error setting SAIF format: %d
\n
"
,
ret
);
return
ret
;
}
return
0
;
}
static
int
tas5720_set_dai_tdm_slot
(
struct
snd_soc_dai
*
dai
,
unsigned
int
tx_mask
,
unsigned
int
rx_mask
,
int
slots
,
int
slot_width
)
{
struct
snd_soc_codec
*
codec
=
dai
->
codec
;
unsigned
int
first_slot
;
int
ret
;
if
(
!
tx_mask
)
{
dev_err
(
codec
->
dev
,
"tx masks must not be 0
\n
"
);
return
-
EINVAL
;
}
/*
* Determine the first slot that is being requested. We will only
* use the first slot that is found since the TAS5720 is a mono
* amplifier.
*/
first_slot
=
__ffs
(
tx_mask
);
if
(
first_slot
>
7
)
{
dev_err
(
codec
->
dev
,
"slot selection out of bounds (%u)
\n
"
,
first_slot
);
return
-
EINVAL
;
}
/* Enable manual TDM slot selection (instead of I2C ID based) */
ret
=
snd_soc_update_bits
(
codec
,
TAS5720_DIGITAL_CTRL1_REG
,
TAS5720_TDM_CFG_SRC
,
TAS5720_TDM_CFG_SRC
);
if
(
ret
<
0
)
goto
error_snd_soc_update_bits
;
/* Configure the TDM slot to process audio from */
ret
=
snd_soc_update_bits
(
codec
,
TAS5720_DIGITAL_CTRL2_REG
,
TAS5720_TDM_SLOT_SEL_MASK
,
first_slot
);
if
(
ret
<
0
)
goto
error_snd_soc_update_bits
;
return
0
;
error_snd_soc_update_bits:
dev_err
(
codec
->
dev
,
"error configuring TDM mode: %d
\n
"
,
ret
);
return
ret
;
}
static
int
tas5720_mute
(
struct
snd_soc_dai
*
dai
,
int
mute
)
{
struct
snd_soc_codec
*
codec
=
dai
->
codec
;
int
ret
;
ret
=
snd_soc_update_bits
(
codec
,
TAS5720_DIGITAL_CTRL2_REG
,
TAS5720_MUTE
,
mute
?
TAS5720_MUTE
:
0
);
if
(
ret
<
0
)
{
dev_err
(
codec
->
dev
,
"error (un-)muting device: %d
\n
"
,
ret
);
return
ret
;
}
return
0
;
}
static
void
tas5720_fault_check_work
(
struct
work_struct
*
work
)
{
struct
tas5720_data
*
tas5720
=
container_of
(
work
,
struct
tas5720_data
,
fault_check_work
.
work
);
struct
device
*
dev
=
tas5720
->
codec
->
dev
;
unsigned
int
curr_fault
;
int
ret
;
ret
=
regmap_read
(
tas5720
->
regmap
,
TAS5720_FAULT_REG
,
&
curr_fault
);
if
(
ret
<
0
)
{
dev_err
(
dev
,
"failed to read FAULT register: %d
\n
"
,
ret
);
goto
out
;
}
/* Check/handle all errors except SAIF clock errors */
curr_fault
&=
TAS5720_OCE
|
TAS5720_DCE
|
TAS5720_OTE
;
/*
* Only flag errors once for a given occurrence. This is needed as
* the TAS5720 will take time clearing the fault condition internally
* during which we don't want to bombard the system with the same
* error message over and over.
*/
if
((
curr_fault
&
TAS5720_OCE
)
&&
!
(
tas5720
->
last_fault
&
TAS5720_OCE
))
dev_crit
(
dev
,
"experienced an over current hardware fault
\n
"
);
if
((
curr_fault
&
TAS5720_DCE
)
&&
!
(
tas5720
->
last_fault
&
TAS5720_DCE
))
dev_crit
(
dev
,
"experienced a DC detection fault
\n
"
);
if
((
curr_fault
&
TAS5720_OTE
)
&&
!
(
tas5720
->
last_fault
&
TAS5720_OTE
))
dev_crit
(
dev
,
"experienced an over temperature fault
\n
"
);
/* Store current fault value so we can detect any changes next time */
tas5720
->
last_fault
=
curr_fault
;
if
(
!
curr_fault
)
goto
out
;
/*
* Periodically toggle SDZ (shutdown bit) H->L->H to clear any latching
* faults as long as a fault condition persists. Always going through
* the full sequence no matter the first return value to minimizes
* chances for the device to end up in shutdown mode.
*/
ret
=
regmap_write_bits
(
tas5720
->
regmap
,
TAS5720_POWER_CTRL_REG
,
TAS5720_SDZ
,
0
);
if
(
ret
<
0
)
dev_err
(
dev
,
"failed to write POWER_CTRL register: %d
\n
"
,
ret
);
ret
=
regmap_write_bits
(
tas5720
->
regmap
,
TAS5720_POWER_CTRL_REG
,
TAS5720_SDZ
,
TAS5720_SDZ
);
if
(
ret
<
0
)
dev_err
(
dev
,
"failed to write POWER_CTRL register: %d
\n
"
,
ret
);
out:
/* Schedule the next fault check at the specified interval */
schedule_delayed_work
(
&
tas5720
->
fault_check_work
,
msecs_to_jiffies
(
TAS5720_FAULT_CHECK_INTERVAL
));
}
static
int
tas5720_codec_probe
(
struct
snd_soc_codec
*
codec
)
{
struct
tas5720_data
*
tas5720
=
snd_soc_codec_get_drvdata
(
codec
);
unsigned
int
device_id
;
int
ret
;
tas5720
->
codec
=
codec
;
ret
=
regulator_bulk_enable
(
ARRAY_SIZE
(
tas5720
->
supplies
),
tas5720
->
supplies
);
if
(
ret
!=
0
)
{
dev_err
(
codec
->
dev
,
"failed to enable supplies: %d
\n
"
,
ret
);
return
ret
;
}
ret
=
regmap_read
(
tas5720
->
regmap
,
TAS5720_DEVICE_ID_REG
,
&
device_id
);
if
(
ret
<
0
)
{
dev_err
(
codec
->
dev
,
"failed to read device ID register: %d
\n
"
,
ret
);
goto
probe_fail
;
}
if
(
device_id
!=
TAS5720_DEVICE_ID
)
{
dev_err
(
codec
->
dev
,
"wrong device ID. expected: %u read: %u
\n
"
,
TAS5720_DEVICE_ID
,
device_id
);
ret
=
-
ENODEV
;
goto
probe_fail
;
}
/* Set device to mute */
ret
=
snd_soc_update_bits
(
codec
,
TAS5720_DIGITAL_CTRL2_REG
,
TAS5720_MUTE
,
TAS5720_MUTE
);
if
(
ret
<
0
)
goto
error_snd_soc_update_bits
;
/*
* Enter shutdown mode - our default when not playing audio - to
* minimize current consumption. On the TAS5720 there is no real down
* side doing so as all device registers are preserved and the wakeup
* of the codec is rather quick which we do using a dapm widget.
*/
ret
=
snd_soc_update_bits
(
codec
,
TAS5720_POWER_CTRL_REG
,
TAS5720_SDZ
,
0
);
if
(
ret
<
0
)
goto
error_snd_soc_update_bits
;
INIT_DELAYED_WORK
(
&
tas5720
->
fault_check_work
,
tas5720_fault_check_work
);
return
0
;
error_snd_soc_update_bits:
dev_err
(
codec
->
dev
,
"error configuring device registers: %d
\n
"
,
ret
);
probe_fail:
regulator_bulk_disable
(
ARRAY_SIZE
(
tas5720
->
supplies
),
tas5720
->
supplies
);
return
ret
;
}
static
int
tas5720_codec_remove
(
struct
snd_soc_codec
*
codec
)
{
struct
tas5720_data
*
tas5720
=
snd_soc_codec_get_drvdata
(
codec
);
int
ret
;
cancel_delayed_work_sync
(
&
tas5720
->
fault_check_work
);
ret
=
regulator_bulk_disable
(
ARRAY_SIZE
(
tas5720
->
supplies
),
tas5720
->
supplies
);
if
(
ret
<
0
)
dev_err
(
codec
->
dev
,
"failed to disable supplies: %d
\n
"
,
ret
);
return
ret
;
};
static
int
tas5720_dac_event
(
struct
snd_soc_dapm_widget
*
w
,
struct
snd_kcontrol
*
kcontrol
,
int
event
)
{
struct
snd_soc_codec
*
codec
=
snd_soc_dapm_to_codec
(
w
->
dapm
);
struct
tas5720_data
*
tas5720
=
snd_soc_codec_get_drvdata
(
codec
);
int
ret
;
if
(
event
&
SND_SOC_DAPM_POST_PMU
)
{
/* Take TAS5720 out of shutdown mode */
ret
=
snd_soc_update_bits
(
codec
,
TAS5720_POWER_CTRL_REG
,
TAS5720_SDZ
,
TAS5720_SDZ
);
if
(
ret
<
0
)
{
dev_err
(
codec
->
dev
,
"error waking codec: %d
\n
"
,
ret
);
return
ret
;
}
/*
* Observe codec shutdown-to-active time. The datasheet only
* lists a nominal value however just use-it as-is without
* additional padding to minimize the delay introduced in
* starting to play audio (actually there is other setup done
* by the ASoC framework that will provide additional delays,
* so we should always be safe).
*/
msleep
(
25
);
/* Turn on TAS5720 periodic fault checking/handling */
tas5720
->
last_fault
=
0
;
schedule_delayed_work
(
&
tas5720
->
fault_check_work
,
msecs_to_jiffies
(
TAS5720_FAULT_CHECK_INTERVAL
));
}
else
if
(
event
&
SND_SOC_DAPM_PRE_PMD
)
{
/* Disable TAS5720 periodic fault checking/handling */
cancel_delayed_work_sync
(
&
tas5720
->
fault_check_work
);
/* Place TAS5720 in shutdown mode to minimize current draw */
ret
=
snd_soc_update_bits
(
codec
,
TAS5720_POWER_CTRL_REG
,
TAS5720_SDZ
,
0
);
if
(
ret
<
0
)
{
dev_err
(
codec
->
dev
,
"error shutting down codec: %d
\n
"
,
ret
);
return
ret
;
}
}
return
0
;
}
#ifdef CONFIG_PM
static
int
tas5720_suspend
(
struct
snd_soc_codec
*
codec
)
{
struct
tas5720_data
*
tas5720
=
snd_soc_codec_get_drvdata
(
codec
);
int
ret
;
regcache_cache_only
(
tas5720
->
regmap
,
true
);
regcache_mark_dirty
(
tas5720
->
regmap
);
ret
=
regulator_bulk_disable
(
ARRAY_SIZE
(
tas5720
->
supplies
),
tas5720
->
supplies
);
if
(
ret
<
0
)
dev_err
(
codec
->
dev
,
"failed to disable supplies: %d
\n
"
,
ret
);
return
ret
;
}
static
int
tas5720_resume
(
struct
snd_soc_codec
*
codec
)
{
struct
tas5720_data
*
tas5720
=
snd_soc_codec_get_drvdata
(
codec
);
int
ret
;
ret
=
regulator_bulk_enable
(
ARRAY_SIZE
(
tas5720
->
supplies
),
tas5720
->
supplies
);
if
(
ret
<
0
)
{
dev_err
(
codec
->
dev
,
"failed to enable supplies: %d
\n
"
,
ret
);
return
ret
;
}
regcache_cache_only
(
tas5720
->
regmap
,
false
);
ret
=
regcache_sync
(
tas5720
->
regmap
);
if
(
ret
<
0
)
{
dev_err
(
codec
->
dev
,
"failed to sync regcache: %d
\n
"
,
ret
);
return
ret
;
}
return
0
;
}
#else
#define tas5720_suspend NULL
#define tas5720_resume NULL
#endif
static
bool
tas5720_is_volatile_reg
(
struct
device
*
dev
,
unsigned
int
reg
)
{
switch
(
reg
)
{
case
TAS5720_DEVICE_ID_REG
:
case
TAS5720_FAULT_REG
:
return
true
;
default:
return
false
;
}
}
static
const
struct
regmap_config
tas5720_regmap_config
=
{
.
reg_bits
=
8
,
.
val_bits
=
8
,
.
max_register
=
TAS5720_MAX_REG
,
.
cache_type
=
REGCACHE_RBTREE
,
.
volatile_reg
=
tas5720_is_volatile_reg
,
};
/*
* DAC analog gain. There are four discrete values to select from, ranging
* from 19.2 dB to 26.3dB.
*/
static
const
DECLARE_TLV_DB_RANGE
(
dac_analog_tlv
,
0x0
,
0x0
,
TLV_DB_SCALE_ITEM
(
1920
,
0
,
0
),
0x1
,
0x1
,
TLV_DB_SCALE_ITEM
(
2070
,
0
,
0
),
0x2
,
0x2
,
TLV_DB_SCALE_ITEM
(
2350
,
0
,
0
),
0x3
,
0x3
,
TLV_DB_SCALE_ITEM
(
2630
,
0
,
0
),
);
/*
* DAC digital volumes. From -103.5 to 24 dB in 0.5 dB steps. Note that
* setting the gain below -100 dB (register value <0x7) is effectively a MUTE
* as per device datasheet.
*/
static
DECLARE_TLV_DB_SCALE
(
dac_tlv
,
-
10350
,
50
,
0
);
static
const
struct
snd_kcontrol_new
tas5720_snd_controls
[]
=
{
SOC_SINGLE_TLV
(
"Speaker Driver Playback Volume"
,
TAS5720_VOLUME_CTRL_REG
,
0
,
0xff
,
0
,
dac_tlv
),
SOC_SINGLE_TLV
(
"Speaker Driver Analog Gain"
,
TAS5720_ANALOG_CTRL_REG
,
TAS5720_ANALOG_GAIN_SHIFT
,
3
,
0
,
dac_analog_tlv
),
};
static
const
struct
snd_soc_dapm_widget
tas5720_dapm_widgets
[]
=
{
SND_SOC_DAPM_AIF_IN
(
"DAC IN"
,
"Playback"
,
0
,
SND_SOC_NOPM
,
0
,
0
),
SND_SOC_DAPM_DAC_E
(
"DAC"
,
NULL
,
SND_SOC_NOPM
,
0
,
0
,
tas5720_dac_event
,
SND_SOC_DAPM_POST_PMU
|
SND_SOC_DAPM_PRE_PMD
),
SND_SOC_DAPM_OUTPUT
(
"OUT"
)
};
static
const
struct
snd_soc_dapm_route
tas5720_audio_map
[]
=
{
{
"DAC"
,
NULL
,
"DAC IN"
},
{
"OUT"
,
NULL
,
"DAC"
},
};
static
struct
snd_soc_codec_driver
soc_codec_dev_tas5720
=
{
.
probe
=
tas5720_codec_probe
,
.
remove
=
tas5720_codec_remove
,
.
suspend
=
tas5720_suspend
,
.
resume
=
tas5720_resume
,
.
controls
=
tas5720_snd_controls
,
.
num_controls
=
ARRAY_SIZE
(
tas5720_snd_controls
),
.
dapm_widgets
=
tas5720_dapm_widgets
,
.
num_dapm_widgets
=
ARRAY_SIZE
(
tas5720_dapm_widgets
),
.
dapm_routes
=
tas5720_audio_map
,
.
num_dapm_routes
=
ARRAY_SIZE
(
tas5720_audio_map
),
};
/* PCM rates supported by the TAS5720 driver */
#define TAS5720_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
/* Formats supported by TAS5720 driver */
#define TAS5720_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE |\
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE)
static
struct
snd_soc_dai_ops
tas5720_speaker_dai_ops
=
{
.
hw_params
=
tas5720_hw_params
,
.
set_fmt
=
tas5720_set_dai_fmt
,
.
set_tdm_slot
=
tas5720_set_dai_tdm_slot
,
.
digital_mute
=
tas5720_mute
,
};
/*
* TAS5720 DAI structure
*
* Note that were are advertising .playback.channels_max = 2 despite this being
* a mono amplifier. The reason for that is that some serial ports such as TI's
* McASP module have a minimum number of channels (2) that they can output.
* Advertising more channels than we have will allow us to interface with such
* a serial port without really any negative side effects as the TAS5720 will
* simply ignore any extra channel(s) asides from the one channel that is
* configured to be played back.
*/
static
struct
snd_soc_dai_driver
tas5720_dai
[]
=
{
{
.
name
=
"tas5720-amplifier"
,
.
playback
=
{
.
stream_name
=
"Playback"
,
.
channels_min
=
1
,
.
channels_max
=
2
,
.
rates
=
TAS5720_RATES
,
.
formats
=
TAS5720_FORMATS
,
},
.
ops
=
&
tas5720_speaker_dai_ops
,
},
};
static
int
tas5720_probe
(
struct
i2c_client
*
client
,
const
struct
i2c_device_id
*
id
)
{
struct
device
*
dev
=
&
client
->
dev
;
struct
tas5720_data
*
data
;
int
ret
;
int
i
;
data
=
devm_kzalloc
(
dev
,
sizeof
(
*
data
),
GFP_KERNEL
);
if
(
!
data
)
return
-
ENOMEM
;
data
->
tas5720_client
=
client
;
data
->
regmap
=
devm_regmap_init_i2c
(
client
,
&
tas5720_regmap_config
);
if
(
IS_ERR
(
data
->
regmap
))
{
ret
=
PTR_ERR
(
data
->
regmap
);
dev_err
(
dev
,
"failed to allocate register map: %d
\n
"
,
ret
);
return
ret
;
}
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
data
->
supplies
);
i
++
)
data
->
supplies
[
i
].
supply
=
tas5720_supply_names
[
i
];
ret
=
devm_regulator_bulk_get
(
dev
,
ARRAY_SIZE
(
data
->
supplies
),
data
->
supplies
);
if
(
ret
!=
0
)
{
dev_err
(
dev
,
"failed to request supplies: %d
\n
"
,
ret
);
return
ret
;
}
dev_set_drvdata
(
dev
,
data
);
ret
=
snd_soc_register_codec
(
&
client
->
dev
,
&
soc_codec_dev_tas5720
,
tas5720_dai
,
ARRAY_SIZE
(
tas5720_dai
));
if
(
ret
<
0
)
{
dev_err
(
dev
,
"failed to register codec: %d
\n
"
,
ret
);
return
ret
;
}
return
0
;
}
static
int
tas5720_remove
(
struct
i2c_client
*
client
)
{
struct
device
*
dev
=
&
client
->
dev
;
snd_soc_unregister_codec
(
dev
);
return
0
;
}
static
const
struct
i2c_device_id
tas5720_id
[]
=
{
{
"tas5720"
,
0
},
{
}
};
MODULE_DEVICE_TABLE
(
i2c
,
tas5720_id
);
#if IS_ENABLED(CONFIG_OF)
static
const
struct
of_device_id
tas5720_of_match
[]
=
{
{
.
compatible
=
"ti,tas5720"
,
},
{
},
};
MODULE_DEVICE_TABLE
(
of
,
tas5720_of_match
);
#endif
static
struct
i2c_driver
tas5720_i2c_driver
=
{
.
driver
=
{
.
name
=
"tas5720"
,
.
of_match_table
=
of_match_ptr
(
tas5720_of_match
),
},
.
probe
=
tas5720_probe
,
.
remove
=
tas5720_remove
,
.
id_table
=
tas5720_id
,
};
module_i2c_driver
(
tas5720_i2c_driver
);
MODULE_AUTHOR
(
"Andreas Dannenberg <dannenberg@ti.com>"
);
MODULE_DESCRIPTION
(
"TAS5720 Audio amplifier driver"
);
MODULE_LICENSE
(
"GPL"
);
sound/soc/codecs/tas5720.h
0 → 100644
View file @
aaa36d3a
/*
* tas5720.h - ALSA SoC Texas Instruments TAS5720 Mono Audio Amplifier
*
* Copyright (C)2015-2016 Texas Instruments Incorporated - http://www.ti.com
*
* Author: Andreas Dannenberg <dannenberg@ti.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* 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.
*/
#ifndef __TAS5720_H__
#define __TAS5720_H__
/* Register Address Map */
#define TAS5720_DEVICE_ID_REG 0x00
#define TAS5720_POWER_CTRL_REG 0x01
#define TAS5720_DIGITAL_CTRL1_REG 0x02
#define TAS5720_DIGITAL_CTRL2_REG 0x03
#define TAS5720_VOLUME_CTRL_REG 0x04
#define TAS5720_ANALOG_CTRL_REG 0x06
#define TAS5720_FAULT_REG 0x08
#define TAS5720_DIGITAL_CLIP2_REG 0x10
#define TAS5720_DIGITAL_CLIP1_REG 0x11
#define TAS5720_MAX_REG TAS5720_DIGITAL_CLIP1_REG
/* TAS5720_DEVICE_ID_REG */
#define TAS5720_DEVICE_ID 0x01
/* TAS5720_POWER_CTRL_REG */
#define TAS5720_DIG_CLIP_MASK GENMASK(7, 2)
#define TAS5720_SLEEP BIT(1)
#define TAS5720_SDZ BIT(0)
/* TAS5720_DIGITAL_CTRL1_REG */
#define TAS5720_HPF_BYPASS BIT(7)
#define TAS5720_TDM_CFG_SRC BIT(6)
#define TAS5720_SSZ_DS BIT(3)
#define TAS5720_SAIF_RIGHTJ_24BIT (0x0)
#define TAS5720_SAIF_RIGHTJ_20BIT (0x1)
#define TAS5720_SAIF_RIGHTJ_18BIT (0x2)
#define TAS5720_SAIF_RIGHTJ_16BIT (0x3)
#define TAS5720_SAIF_I2S (0x4)
#define TAS5720_SAIF_LEFTJ (0x5)
#define TAS5720_SAIF_FORMAT_MASK GENMASK(2, 0)
/* TAS5720_DIGITAL_CTRL2_REG */
#define TAS5720_MUTE BIT(4)
#define TAS5720_TDM_SLOT_SEL_MASK GENMASK(2, 0)
/* TAS5720_ANALOG_CTRL_REG */
#define TAS5720_PWM_RATE_6_3_FSYNC (0x0 << 4)
#define TAS5720_PWM_RATE_8_4_FSYNC (0x1 << 4)
#define TAS5720_PWM_RATE_10_5_FSYNC (0x2 << 4)
#define TAS5720_PWM_RATE_12_6_FSYNC (0x3 << 4)
#define TAS5720_PWM_RATE_14_7_FSYNC (0x4 << 4)
#define TAS5720_PWM_RATE_16_8_FSYNC (0x5 << 4)
#define TAS5720_PWM_RATE_20_10_FSYNC (0x6 << 4)
#define TAS5720_PWM_RATE_24_12_FSYNC (0x7 << 4)
#define TAS5720_PWM_RATE_MASK GENMASK(6, 4)
#define TAS5720_ANALOG_GAIN_19_2DBV (0x0 << 2)
#define TAS5720_ANALOG_GAIN_20_7DBV (0x1 << 2)
#define TAS5720_ANALOG_GAIN_23_5DBV (0x2 << 2)
#define TAS5720_ANALOG_GAIN_26_3DBV (0x3 << 2)
#define TAS5720_ANALOG_GAIN_MASK GENMASK(3, 2)
#define TAS5720_ANALOG_GAIN_SHIFT (0x2)
/* TAS5720_FAULT_REG */
#define TAS5720_OC_THRESH_100PCT (0x0 << 4)
#define TAS5720_OC_THRESH_75PCT (0x1 << 4)
#define TAS5720_OC_THRESH_50PCT (0x2 << 4)
#define TAS5720_OC_THRESH_25PCT (0x3 << 4)
#define TAS5720_OC_THRESH_MASK GENMASK(5, 4)
#define TAS5720_CLKE BIT(3)
#define TAS5720_OCE BIT(2)
#define TAS5720_DCE BIT(1)
#define TAS5720_OTE BIT(0)
#define TAS5720_FAULT_MASK GENMASK(3, 0)
/* TAS5720_DIGITAL_CLIP1_REG */
#define TAS5720_CLIP1_MASK GENMASK(7, 2)
#define TAS5720_CLIP1_SHIFT (0x2)
#endif
/* __TAS5720_H__ */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment