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
nexedi
linux
Commits
56fe4897
Commit
56fe4897
authored
Mar 13, 2014
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'asoc/topic/tlv320aic31xx' into asoc-next
parents
1727428d
e00447fa
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
1628 additions
and
0 deletions
+1628
-0
Documentation/devicetree/bindings/sound/tlv320aic31xx.txt
Documentation/devicetree/bindings/sound/tlv320aic31xx.txt
+61
-0
include/dt-bindings/sound/tlv320aic31xx-micbias.h
include/dt-bindings/sound/tlv320aic31xx-micbias.h
+8
-0
sound/soc/codecs/Kconfig
sound/soc/codecs/Kconfig
+4
-0
sound/soc/codecs/Makefile
sound/soc/codecs/Makefile
+2
-0
sound/soc/codecs/tlv320aic31xx.c
sound/soc/codecs/tlv320aic31xx.c
+1295
-0
sound/soc/codecs/tlv320aic31xx.h
sound/soc/codecs/tlv320aic31xx.h
+258
-0
No files found.
Documentation/devicetree/bindings/sound/tlv320aic31xx.txt
0 → 100644
View file @
56fe4897
Texas Instruments - tlv320aic31xx Codec module
The tlv320aic31xx serial control bus communicates through I2C protocols
Required properties:
- compatible - "string" - One of:
"ti,tlv320aic310x" - Generic TLV320AIC31xx with mono speaker amp
"ti,tlv320aic311x" - Generic TLV320AIC31xx with stereo speaker amp
"ti,tlv320aic3100" - TLV320AIC3100 (mono speaker amp, no MiniDSP)
"ti,tlv320aic3110" - TLV320AIC3110 (stereo speaker amp, no MiniDSP)
"ti,tlv320aic3120" - TLV320AIC3120 (mono speaker amp, MiniDSP)
"ti,tlv320aic3111" - TLV320AIC3111 (stereo speaker amp, MiniDSP)
- reg - <int> - I2C slave address
Optional properties:
- gpio-reset - gpio pin number used for codec reset
- ai31xx-micbias-vg - MicBias Voltage setting
1 or MICBIAS_2_0V - MICBIAS output is powered to 2.0V
2 or MICBIAS_2_5V - MICBIAS output is powered to 2.5V
3 or MICBIAS_AVDD - MICBIAS output is connected to AVDD
If this node is not mentioned or if the value is unknown, then
micbias is set to 2.0V.
- HPVDD-supply, SPRVDD-supply, SPLVDD-supply, AVDD-supply, IOVDD-supply,
DVDD-supply : power supplies for the device as covered in
Documentation/devicetree/bindings/regulator/regulator.txt
CODEC output pins:
* HPL
* HPR
* SPL, devices with stereo speaker amp
* SPR, devices with stereo speaker amp
* SPK, devices with mono speaker amp
* MICBIAS
CODEC input pins:
* MIC1LP
* MIC1RP
* MIC1LM
The pins can be used in referring sound node's audio-routing property.
Example:
#include <dt-bindings/sound/tlv320aic31xx-micbias.h>
tlv320aic31xx: tlv320aic31xx@18 {
compatible = "ti,tlv320aic311x";
reg = <0x18>;
ai31xx-micbias-vg = <MICBIAS_OFF>;
HPVDD-supply = <®ulator>;
SPRVDD-supply = <®ulator>;
SPLVDD-supply = <®ulator>;
AVDD-supply = <®ulator>;
IOVDD-supply = <®ulator>;
DVDD-supply = <®ulator>;
};
include/dt-bindings/sound/tlv320aic31xx-micbias.h
0 → 100644
View file @
56fe4897
#ifndef __DT_TLV320AIC31XX_MICBIAS_H
#define __DT_TLV320AIC31XX_MICBIAS_H
#define MICBIAS_2_0V 1
#define MICBIAS_2_5V 2
#define MICBIAS_AVDDV 3
#endif
/* __DT_TLV320AIC31XX_MICBIAS_H */
sound/soc/codecs/Kconfig
View file @
56fe4897
...
...
@@ -85,6 +85,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_TLV320AIC23_I2C if I2C
select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
select SND_SOC_TLV320AIC26 if SPI_MASTER
select SND_SOC_TLV320AIC31XX if I2C
select SND_SOC_TLV320AIC32X4 if I2C
select SND_SOC_TLV320AIC3X if I2C
select SND_SOC_TPA6130A2 if I2C
...
...
@@ -449,6 +450,9 @@ config SND_SOC_TLV320AIC26
tristate
depends on SPI
config SND_SOC_TLV320AIC31XX
tristate
config SND_SOC_TLV320AIC32X4
tristate
...
...
sound/soc/codecs/Makefile
View file @
56fe4897
...
...
@@ -79,6 +79,7 @@ snd-soc-tlv320aic23-objs := tlv320aic23.o
snd-soc-tlv320aic23-i2c-objs
:=
tlv320aic23-i2c.o
snd-soc-tlv320aic23-spi-objs
:=
tlv320aic23-spi.o
snd-soc-tlv320aic26-objs
:=
tlv320aic26.o
snd-soc-tlv320aic31xx-objs
:=
tlv320aic31xx.o
snd-soc-tlv320aic32x4-objs
:=
tlv320aic32x4.o
snd-soc-tlv320aic3x-objs
:=
tlv320aic3x.o
snd-soc-tlv320dac33-objs
:=
tlv320dac33.o
...
...
@@ -223,6 +224,7 @@ 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_SPI)
+=
snd-soc-tlv320aic23-spi.o
obj-$(CONFIG_SND_SOC_TLV320AIC26)
+=
snd-soc-tlv320aic26.o
obj-$(CONFIG_SND_SOC_TLV320AIC31XX)
+=
snd-soc-tlv320aic31xx.o
obj-$(CONFIG_SND_SOC_TLV320AIC32X4)
+=
snd-soc-tlv320aic32x4.o
obj-$(CONFIG_SND_SOC_TLV320AIC3X)
+=
snd-soc-tlv320aic3x.o
obj-$(CONFIG_SND_SOC_TLV320DAC33)
+=
snd-soc-tlv320dac33.o
...
...
sound/soc/codecs/tlv320aic31xx.c
0 → 100644
View file @
56fe4897
/*
* ALSA SoC TLV320AIC31XX codec driver
*
* Copyright (C) 2014 Texas Instruments, Inc.
*
* Author: Jyri Sarha <jsarha@ti.com>
*
* Based on ground work by: Ajit Kulkarni <x0175765@ti.com>
*
* This package 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 PACKAGE IS PROVIDED AS IS AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* The TLV320AIC31xx series of audio codec is a low-power, highly integrated
* high performance codec which provides a stereo DAC, a mono ADC,
* and mono/stereo Class-D speaker driver.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <dt-bindings/sound/tlv320aic31xx-micbias.h>
#include "tlv320aic31xx.h"
static
const
struct
reg_default
aic31xx_reg_defaults
[]
=
{
{
AIC31XX_CLKMUX
,
0x00
},
{
AIC31XX_PLLPR
,
0x11
},
{
AIC31XX_PLLJ
,
0x04
},
{
AIC31XX_PLLDMSB
,
0x00
},
{
AIC31XX_PLLDLSB
,
0x00
},
{
AIC31XX_NDAC
,
0x01
},
{
AIC31XX_MDAC
,
0x01
},
{
AIC31XX_DOSRMSB
,
0x00
},
{
AIC31XX_DOSRLSB
,
0x80
},
{
AIC31XX_NADC
,
0x01
},
{
AIC31XX_MADC
,
0x01
},
{
AIC31XX_AOSR
,
0x80
},
{
AIC31XX_IFACE1
,
0x00
},
{
AIC31XX_DATA_OFFSET
,
0x00
},
{
AIC31XX_IFACE2
,
0x00
},
{
AIC31XX_BCLKN
,
0x01
},
{
AIC31XX_DACSETUP
,
0x14
},
{
AIC31XX_DACMUTE
,
0x0c
},
{
AIC31XX_LDACVOL
,
0x00
},
{
AIC31XX_RDACVOL
,
0x00
},
{
AIC31XX_ADCSETUP
,
0x00
},
{
AIC31XX_ADCFGA
,
0x80
},
{
AIC31XX_ADCVOL
,
0x00
},
{
AIC31XX_HPDRIVER
,
0x04
},
{
AIC31XX_SPKAMP
,
0x06
},
{
AIC31XX_DACMIXERROUTE
,
0x00
},
{
AIC31XX_LANALOGHPL
,
0x7f
},
{
AIC31XX_RANALOGHPR
,
0x7f
},
{
AIC31XX_LANALOGSPL
,
0x7f
},
{
AIC31XX_RANALOGSPR
,
0x7f
},
{
AIC31XX_HPLGAIN
,
0x02
},
{
AIC31XX_HPRGAIN
,
0x02
},
{
AIC31XX_SPLGAIN
,
0x00
},
{
AIC31XX_SPRGAIN
,
0x00
},
{
AIC31XX_MICBIAS
,
0x00
},
{
AIC31XX_MICPGA
,
0x80
},
{
AIC31XX_MICPGAPI
,
0x00
},
{
AIC31XX_MICPGAMI
,
0x00
},
};
static
bool
aic31xx_volatile
(
struct
device
*
dev
,
unsigned
int
reg
)
{
switch
(
reg
)
{
case
AIC31XX_PAGECTL
:
/* regmap implementation requires this */
case
AIC31XX_RESET
:
/* always clears after write */
case
AIC31XX_OT_FLAG
:
case
AIC31XX_ADCFLAG
:
case
AIC31XX_DACFLAG1
:
case
AIC31XX_DACFLAG2
:
case
AIC31XX_OFFLAG
:
/* Sticky interrupt flags */
case
AIC31XX_INTRDACFLAG
:
/* Sticky interrupt flags */
case
AIC31XX_INTRADCFLAG
:
/* Sticky interrupt flags */
case
AIC31XX_INTRDACFLAG2
:
case
AIC31XX_INTRADCFLAG2
:
return
true
;
}
return
false
;
}
static
bool
aic31xx_writeable
(
struct
device
*
dev
,
unsigned
int
reg
)
{
switch
(
reg
)
{
case
AIC31XX_OT_FLAG
:
case
AIC31XX_ADCFLAG
:
case
AIC31XX_DACFLAG1
:
case
AIC31XX_DACFLAG2
:
case
AIC31XX_OFFLAG
:
/* Sticky interrupt flags */
case
AIC31XX_INTRDACFLAG
:
/* Sticky interrupt flags */
case
AIC31XX_INTRADCFLAG
:
/* Sticky interrupt flags */
case
AIC31XX_INTRDACFLAG2
:
case
AIC31XX_INTRADCFLAG2
:
return
false
;
}
return
true
;
}
static
const
struct
regmap_range_cfg
aic31xx_ranges
[]
=
{
{
.
range_min
=
0
,
.
range_max
=
12
*
128
,
.
selector_reg
=
AIC31XX_PAGECTL
,
.
selector_mask
=
0xff
,
.
selector_shift
=
0
,
.
window_start
=
0
,
.
window_len
=
128
,
},
};
struct
regmap_config
aic31xx_i2c_regmap
=
{
.
reg_bits
=
8
,
.
val_bits
=
8
,
.
writeable_reg
=
aic31xx_writeable
,
.
volatile_reg
=
aic31xx_volatile
,
.
reg_defaults
=
aic31xx_reg_defaults
,
.
num_reg_defaults
=
ARRAY_SIZE
(
aic31xx_reg_defaults
),
.
cache_type
=
REGCACHE_RBTREE
,
.
ranges
=
aic31xx_ranges
,
.
num_ranges
=
ARRAY_SIZE
(
aic31xx_ranges
),
.
max_register
=
12
*
128
,
};
#define AIC31XX_NUM_SUPPLIES 6
static
const
char
*
const
aic31xx_supply_names
[
AIC31XX_NUM_SUPPLIES
]
=
{
"HPVDD"
,
"SPRVDD"
,
"SPLVDD"
,
"AVDD"
,
"IOVDD"
,
"DVDD"
,
};
struct
aic31xx_disable_nb
{
struct
notifier_block
nb
;
struct
aic31xx_priv
*
aic31xx
;
};
struct
aic31xx_priv
{
struct
snd_soc_codec
*
codec
;
u8
i2c_regs_status
;
struct
device
*
dev
;
struct
regmap
*
regmap
;
struct
aic31xx_pdata
pdata
;
struct
regulator_bulk_data
supplies
[
AIC31XX_NUM_SUPPLIES
];
struct
aic31xx_disable_nb
disable_nb
[
AIC31XX_NUM_SUPPLIES
];
unsigned
int
sysclk
;
int
rate_div_line
;
};
struct
aic31xx_rate_divs
{
u32
mclk
;
u32
rate
;
u8
p_val
;
u8
pll_j
;
u16
pll_d
;
u16
dosr
;
u8
ndac
;
u8
mdac
;
u8
aosr
;
u8
nadc
;
u8
madc
;
};
/* ADC dividers can be disabled by cofiguring them to 0 */
static
const
struct
aic31xx_rate_divs
aic31xx_divs
[]
=
{
/* mclk rate pll: p j d dosr ndac mdac aors nadc madc */
/* 8k rate */
{
12000000
,
8000
,
1
,
8
,
1920
,
128
,
48
,
2
,
128
,
48
,
2
},
{
24000000
,
8000
,
2
,
8
,
1920
,
128
,
48
,
2
,
128
,
48
,
2
},
{
25000000
,
8000
,
2
,
7
,
8643
,
128
,
48
,
2
,
128
,
48
,
2
},
/* 11.025k rate */
{
12000000
,
11025
,
1
,
7
,
5264
,
128
,
32
,
2
,
128
,
32
,
2
},
{
24000000
,
11025
,
2
,
7
,
5264
,
128
,
32
,
2
,
128
,
32
,
2
},
{
25000000
,
11025
,
2
,
7
,
2253
,
128
,
32
,
2
,
128
,
32
,
2
},
/* 16k rate */
{
12000000
,
16000
,
1
,
8
,
1920
,
128
,
24
,
2
,
128
,
24
,
2
},
{
24000000
,
16000
,
2
,
8
,
1920
,
128
,
24
,
2
,
128
,
24
,
2
},
{
25000000
,
16000
,
2
,
7
,
8643
,
128
,
24
,
2
,
128
,
24
,
2
},
/* 22.05k rate */
{
12000000
,
22050
,
1
,
7
,
5264
,
128
,
16
,
2
,
128
,
16
,
2
},
{
24000000
,
22050
,
2
,
7
,
5264
,
128
,
16
,
2
,
128
,
16
,
2
},
{
25000000
,
22050
,
2
,
7
,
2253
,
128
,
16
,
2
,
128
,
16
,
2
},
/* 32k rate */
{
12000000
,
32000
,
1
,
8
,
1920
,
128
,
12
,
2
,
128
,
12
,
2
},
{
24000000
,
32000
,
2
,
8
,
1920
,
128
,
12
,
2
,
128
,
12
,
2
},
{
25000000
,
32000
,
2
,
7
,
8643
,
128
,
12
,
2
,
128
,
12
,
2
},
/* 44.1k rate */
{
12000000
,
44100
,
1
,
7
,
5264
,
128
,
8
,
2
,
128
,
8
,
2
},
{
24000000
,
44100
,
2
,
7
,
5264
,
128
,
8
,
2
,
128
,
8
,
2
},
{
25000000
,
44100
,
2
,
7
,
2253
,
128
,
8
,
2
,
128
,
8
,
2
},
/* 48k rate */
{
12000000
,
48000
,
1
,
8
,
1920
,
128
,
8
,
2
,
128
,
8
,
2
},
{
24000000
,
48000
,
2
,
8
,
1920
,
128
,
8
,
2
,
128
,
8
,
2
},
{
25000000
,
48000
,
2
,
7
,
8643
,
128
,
8
,
2
,
128
,
8
,
2
},
/* 88.2k rate */
{
12000000
,
88200
,
1
,
7
,
5264
,
64
,
8
,
2
,
64
,
8
,
2
},
{
24000000
,
88200
,
2
,
7
,
5264
,
64
,
8
,
2
,
64
,
8
,
2
},
{
25000000
,
88200
,
2
,
7
,
2253
,
64
,
8
,
2
,
64
,
8
,
2
},
/* 96k rate */
{
12000000
,
96000
,
1
,
8
,
1920
,
64
,
8
,
2
,
64
,
8
,
2
},
{
24000000
,
96000
,
2
,
8
,
1920
,
64
,
8
,
2
,
64
,
8
,
2
},
{
25000000
,
96000
,
2
,
7
,
8643
,
64
,
8
,
2
,
64
,
8
,
2
},
/* 176.4k rate */
{
12000000
,
176400
,
1
,
7
,
5264
,
32
,
8
,
2
,
32
,
8
,
2
},
{
24000000
,
176400
,
2
,
7
,
5264
,
32
,
8
,
2
,
32
,
8
,
2
},
{
25000000
,
176400
,
2
,
7
,
2253
,
32
,
8
,
2
,
32
,
8
,
2
},
/* 192k rate */
{
12000000
,
192000
,
1
,
8
,
1920
,
32
,
8
,
2
,
32
,
8
,
2
},
{
24000000
,
192000
,
2
,
8
,
1920
,
32
,
8
,
2
,
32
,
8
,
2
},
{
25000000
,
192000
,
2
,
7
,
8643
,
32
,
8
,
2
,
32
,
8
,
2
},
};
static
const
char
*
const
ldac_in_text
[]
=
{
"Off"
,
"Left Data"
,
"Right Data"
,
"Mono"
};
static
const
char
*
const
rdac_in_text
[]
=
{
"Off"
,
"Right Data"
,
"Left Data"
,
"Mono"
};
static
SOC_ENUM_SINGLE_DECL
(
ldac_in_enum
,
AIC31XX_DACSETUP
,
4
,
ldac_in_text
);
static
SOC_ENUM_SINGLE_DECL
(
rdac_in_enum
,
AIC31XX_DACSETUP
,
2
,
rdac_in_text
);
static
const
char
*
const
mic_select_text
[]
=
{
"Off"
,
"FFR 10 Ohm"
,
"FFR 20 Ohm"
,
"FFR 40 Ohm"
};
static
const
SOC_ENUM_SINGLE_DECL
(
mic1lp_p_enum
,
AIC31XX_MICPGAPI
,
6
,
mic_select_text
);
static
const
SOC_ENUM_SINGLE_DECL
(
mic1rp_p_enum
,
AIC31XX_MICPGAPI
,
4
,
mic_select_text
);
static
const
SOC_ENUM_SINGLE_DECL
(
mic1lm_p_enum
,
AIC31XX_MICPGAPI
,
2
,
mic_select_text
);
static
const
SOC_ENUM_SINGLE_DECL
(
cm_m_enum
,
AIC31XX_MICPGAMI
,
6
,
mic_select_text
);
static
const
SOC_ENUM_SINGLE_DECL
(
mic1lm_m_enum
,
AIC31XX_MICPGAMI
,
4
,
mic_select_text
);
static
const
DECLARE_TLV_DB_SCALE
(
dac_vol_tlv
,
-
6350
,
50
,
0
);
static
const
DECLARE_TLV_DB_SCALE
(
adc_fgain_tlv
,
0
,
10
,
0
);
static
const
DECLARE_TLV_DB_SCALE
(
adc_cgain_tlv
,
-
2000
,
50
,
0
);
static
const
DECLARE_TLV_DB_SCALE
(
mic_pga_tlv
,
0
,
50
,
0
);
static
const
DECLARE_TLV_DB_SCALE
(
hp_drv_tlv
,
0
,
100
,
0
);
static
const
DECLARE_TLV_DB_SCALE
(
class_D_drv_tlv
,
600
,
600
,
0
);
static
const
DECLARE_TLV_DB_SCALE
(
hp_vol_tlv
,
-
6350
,
50
,
0
);
static
const
DECLARE_TLV_DB_SCALE
(
sp_vol_tlv
,
-
6350
,
50
,
0
);
/*
* controls to be exported to the user space
*/
static
const
struct
snd_kcontrol_new
aic31xx_snd_controls
[]
=
{
SOC_DOUBLE_R_S_TLV
(
"DAC Playback Volume"
,
AIC31XX_LDACVOL
,
AIC31XX_RDACVOL
,
0
,
-
127
,
48
,
7
,
0
,
dac_vol_tlv
),
SOC_SINGLE_TLV
(
"ADC Fine Capture Volume"
,
AIC31XX_ADCFGA
,
4
,
4
,
1
,
adc_fgain_tlv
),
SOC_SINGLE
(
"ADC Capture Switch"
,
AIC31XX_ADCFGA
,
7
,
1
,
1
),
SOC_DOUBLE_R_S_TLV
(
"ADC Capture Volume"
,
AIC31XX_ADCVOL
,
AIC31XX_ADCVOL
,
0
,
-
24
,
40
,
6
,
0
,
adc_cgain_tlv
),
SOC_SINGLE_TLV
(
"Mic PGA Capture Volume"
,
AIC31XX_MICPGA
,
0
,
119
,
0
,
mic_pga_tlv
),
SOC_DOUBLE_R
(
"HP Driver Playback Switch"
,
AIC31XX_HPLGAIN
,
AIC31XX_HPRGAIN
,
2
,
1
,
0
),
SOC_DOUBLE_R_TLV
(
"HP Driver Playback Volume"
,
AIC31XX_HPLGAIN
,
AIC31XX_HPRGAIN
,
3
,
0x09
,
0
,
hp_drv_tlv
),
SOC_DOUBLE_R_TLV
(
"HP Analog Playback Volume"
,
AIC31XX_LANALOGHPL
,
AIC31XX_RANALOGHPR
,
0
,
0x7F
,
1
,
hp_vol_tlv
),
};
static
const
struct
snd_kcontrol_new
aic311x_snd_controls
[]
=
{
SOC_DOUBLE_R
(
"Speaker Driver Playback Switch"
,
AIC31XX_SPLGAIN
,
AIC31XX_SPRGAIN
,
2
,
1
,
0
),
SOC_DOUBLE_R_TLV
(
"Speaker Driver Playback Volume"
,
AIC31XX_SPLGAIN
,
AIC31XX_SPRGAIN
,
3
,
3
,
0
,
class_D_drv_tlv
),
SOC_DOUBLE_R_TLV
(
"Speaker Analog Playback Volume"
,
AIC31XX_LANALOGSPL
,
AIC31XX_RANALOGSPR
,
0
,
0x7F
,
1
,
sp_vol_tlv
),
};
static
const
struct
snd_kcontrol_new
aic310x_snd_controls
[]
=
{
SOC_SINGLE
(
"Speaker Driver Playback Switch"
,
AIC31XX_SPLGAIN
,
2
,
1
,
0
),
SOC_SINGLE_TLV
(
"Speaker Driver Playback Volume"
,
AIC31XX_SPLGAIN
,
3
,
3
,
0
,
class_D_drv_tlv
),
SOC_SINGLE_TLV
(
"Speaker Analog Playback Volume"
,
AIC31XX_LANALOGSPL
,
0
,
0x7F
,
1
,
sp_vol_tlv
),
};
static
const
struct
snd_kcontrol_new
ldac_in_control
=
SOC_DAPM_ENUM
(
"DAC Left Input"
,
ldac_in_enum
);
static
const
struct
snd_kcontrol_new
rdac_in_control
=
SOC_DAPM_ENUM
(
"DAC Right Input"
,
rdac_in_enum
);
int
aic31xx_wait_bits
(
struct
aic31xx_priv
*
aic31xx
,
unsigned
int
reg
,
unsigned
int
mask
,
unsigned
int
wbits
,
int
sleep
,
int
count
)
{
unsigned
int
bits
;
int
counter
=
count
;
int
ret
=
regmap_read
(
aic31xx
->
regmap
,
reg
,
&
bits
);
while
((
bits
&
mask
)
!=
wbits
&&
counter
&&
!
ret
)
{
usleep_range
(
sleep
,
sleep
*
2
);
ret
=
regmap_read
(
aic31xx
->
regmap
,
reg
,
&
bits
);
counter
--
;
}
if
((
bits
&
mask
)
!=
wbits
)
{
dev_err
(
aic31xx
->
dev
,
"%s: Failed! 0x%x was 0x%x expected 0x%x (%d, 0x%x, %d us)
\n
"
,
__func__
,
reg
,
bits
,
wbits
,
ret
,
mask
,
(
count
-
counter
)
*
sleep
);
ret
=
-
1
;
}
return
ret
;
}
#define WIDGET_BIT(reg, shift) (((shift) << 8) | (reg))
static
int
aic31xx_dapm_power_event
(
struct
snd_soc_dapm_widget
*
w
,
struct
snd_kcontrol
*
kcontrol
,
int
event
)
{
struct
aic31xx_priv
*
aic31xx
=
snd_soc_codec_get_drvdata
(
w
->
codec
);
unsigned
int
reg
=
AIC31XX_DACFLAG1
;
unsigned
int
mask
;
switch
(
WIDGET_BIT
(
w
->
reg
,
w
->
shift
))
{
case
WIDGET_BIT
(
AIC31XX_DACSETUP
,
7
):
mask
=
AIC31XX_LDACPWRSTATUS_MASK
;
break
;
case
WIDGET_BIT
(
AIC31XX_DACSETUP
,
6
):
mask
=
AIC31XX_RDACPWRSTATUS_MASK
;
break
;
case
WIDGET_BIT
(
AIC31XX_HPDRIVER
,
7
):
mask
=
AIC31XX_HPLDRVPWRSTATUS_MASK
;
break
;
case
WIDGET_BIT
(
AIC31XX_HPDRIVER
,
6
):
mask
=
AIC31XX_HPRDRVPWRSTATUS_MASK
;
break
;
case
WIDGET_BIT
(
AIC31XX_SPKAMP
,
7
):
mask
=
AIC31XX_SPLDRVPWRSTATUS_MASK
;
break
;
case
WIDGET_BIT
(
AIC31XX_SPKAMP
,
6
):
mask
=
AIC31XX_SPRDRVPWRSTATUS_MASK
;
break
;
case
WIDGET_BIT
(
AIC31XX_ADCSETUP
,
7
):
mask
=
AIC31XX_ADCPWRSTATUS_MASK
;
reg
=
AIC31XX_ADCFLAG
;
break
;
default:
dev_err
(
w
->
codec
->
dev
,
"Unknown widget '%s' calling %s/n"
,
w
->
name
,
__func__
);
return
-
EINVAL
;
}
switch
(
event
)
{
case
SND_SOC_DAPM_POST_PMU
:
return
aic31xx_wait_bits
(
aic31xx
,
reg
,
mask
,
mask
,
5000
,
100
);
case
SND_SOC_DAPM_POST_PMD
:
return
aic31xx_wait_bits
(
aic31xx
,
reg
,
mask
,
0
,
5000
,
100
);
default:
dev_dbg
(
w
->
codec
->
dev
,
"Unhandled dapm widget event %d from %s
\n
"
,
event
,
w
->
name
);
}
return
0
;
}
static
const
struct
snd_kcontrol_new
left_output_switches
[]
=
{
SOC_DAPM_SINGLE
(
"From Left DAC"
,
AIC31XX_DACMIXERROUTE
,
6
,
1
,
0
),
SOC_DAPM_SINGLE
(
"From MIC1LP"
,
AIC31XX_DACMIXERROUTE
,
5
,
1
,
0
),
SOC_DAPM_SINGLE
(
"From MIC1RP"
,
AIC31XX_DACMIXERROUTE
,
4
,
1
,
0
),
};
static
const
struct
snd_kcontrol_new
right_output_switches
[]
=
{
SOC_DAPM_SINGLE
(
"From Right DAC"
,
AIC31XX_DACMIXERROUTE
,
2
,
1
,
0
),
SOC_DAPM_SINGLE
(
"From MIC1RP"
,
AIC31XX_DACMIXERROUTE
,
1
,
1
,
0
),
};
static
const
struct
snd_kcontrol_new
p_term_mic1lp
=
SOC_DAPM_ENUM
(
"MIC1LP P-Terminal"
,
mic1lp_p_enum
);
static
const
struct
snd_kcontrol_new
p_term_mic1rp
=
SOC_DAPM_ENUM
(
"MIC1RP P-Terminal"
,
mic1rp_p_enum
);
static
const
struct
snd_kcontrol_new
p_term_mic1lm
=
SOC_DAPM_ENUM
(
"MIC1LM P-Terminal"
,
mic1lm_p_enum
);
static
const
struct
snd_kcontrol_new
m_term_mic1lm
=
SOC_DAPM_ENUM
(
"MIC1LM M-Terminal"
,
mic1lm_m_enum
);
static
const
struct
snd_kcontrol_new
aic31xx_dapm_hpl_switch
=
SOC_DAPM_SINGLE
(
"Switch"
,
AIC31XX_LANALOGHPL
,
7
,
1
,
0
);
static
const
struct
snd_kcontrol_new
aic31xx_dapm_hpr_switch
=
SOC_DAPM_SINGLE
(
"Switch"
,
AIC31XX_RANALOGHPR
,
7
,
1
,
0
);
static
const
struct
snd_kcontrol_new
aic31xx_dapm_spl_switch
=
SOC_DAPM_SINGLE
(
"Switch"
,
AIC31XX_LANALOGSPL
,
7
,
1
,
0
);
static
const
struct
snd_kcontrol_new
aic31xx_dapm_spr_switch
=
SOC_DAPM_SINGLE
(
"Switch"
,
AIC31XX_RANALOGSPR
,
7
,
1
,
0
);
static
int
mic_bias_event
(
struct
snd_soc_dapm_widget
*
w
,
struct
snd_kcontrol
*
kcontrol
,
int
event
)
{
struct
snd_soc_codec
*
codec
=
w
->
codec
;
struct
aic31xx_priv
*
aic31xx
=
snd_soc_codec_get_drvdata
(
codec
);
switch
(
event
)
{
case
SND_SOC_DAPM_POST_PMU
:
/* change mic bias voltage to user defined */
snd_soc_update_bits
(
codec
,
AIC31XX_MICBIAS
,
AIC31XX_MICBIAS_MASK
,
aic31xx
->
pdata
.
micbias_vg
<<
AIC31XX_MICBIAS_SHIFT
);
dev_dbg
(
codec
->
dev
,
"%s: turned on
\n
"
,
__func__
);
break
;
case
SND_SOC_DAPM_PRE_PMD
:
/* turn mic bias off */
snd_soc_update_bits
(
codec
,
AIC31XX_MICBIAS
,
AIC31XX_MICBIAS_MASK
,
0
);
dev_dbg
(
codec
->
dev
,
"%s: turned off
\n
"
,
__func__
);
break
;
}
return
0
;
}
static
const
struct
snd_soc_dapm_widget
aic31xx_dapm_widgets
[]
=
{
SND_SOC_DAPM_AIF_IN
(
"DAC IN"
,
"DAC Playback"
,
0
,
SND_SOC_NOPM
,
0
,
0
),
SND_SOC_DAPM_MUX
(
"DAC Left Input"
,
SND_SOC_NOPM
,
0
,
0
,
&
ldac_in_control
),
SND_SOC_DAPM_MUX
(
"DAC Right Input"
,
SND_SOC_NOPM
,
0
,
0
,
&
rdac_in_control
),
/* DACs */
SND_SOC_DAPM_DAC_E
(
"DAC Left"
,
"Left Playback"
,
AIC31XX_DACSETUP
,
7
,
0
,
aic31xx_dapm_power_event
,
SND_SOC_DAPM_POST_PMU
|
SND_SOC_DAPM_POST_PMD
),
SND_SOC_DAPM_DAC_E
(
"DAC Right"
,
"Right Playback"
,
AIC31XX_DACSETUP
,
6
,
0
,
aic31xx_dapm_power_event
,
SND_SOC_DAPM_POST_PMU
|
SND_SOC_DAPM_POST_PMD
),
/* Output Mixers */
SND_SOC_DAPM_MIXER
(
"Output Left"
,
SND_SOC_NOPM
,
0
,
0
,
left_output_switches
,
ARRAY_SIZE
(
left_output_switches
)),
SND_SOC_DAPM_MIXER
(
"Output Right"
,
SND_SOC_NOPM
,
0
,
0
,
right_output_switches
,
ARRAY_SIZE
(
right_output_switches
)),
SND_SOC_DAPM_SWITCH
(
"HP Left"
,
SND_SOC_NOPM
,
0
,
0
,
&
aic31xx_dapm_hpl_switch
),
SND_SOC_DAPM_SWITCH
(
"HP Right"
,
SND_SOC_NOPM
,
0
,
0
,
&
aic31xx_dapm_hpr_switch
),
/* Output drivers */
SND_SOC_DAPM_OUT_DRV_E
(
"HPL Driver"
,
AIC31XX_HPDRIVER
,
7
,
0
,
NULL
,
0
,
aic31xx_dapm_power_event
,
SND_SOC_DAPM_POST_PMD
|
SND_SOC_DAPM_POST_PMU
),
SND_SOC_DAPM_OUT_DRV_E
(
"HPR Driver"
,
AIC31XX_HPDRIVER
,
6
,
0
,
NULL
,
0
,
aic31xx_dapm_power_event
,
SND_SOC_DAPM_POST_PMD
|
SND_SOC_DAPM_POST_PMU
),
/* ADC */
SND_SOC_DAPM_ADC_E
(
"ADC"
,
"Capture"
,
AIC31XX_ADCSETUP
,
7
,
0
,
aic31xx_dapm_power_event
,
SND_SOC_DAPM_POST_PMU
|
SND_SOC_DAPM_POST_PMD
),
/* Input Selection to MIC_PGA */
SND_SOC_DAPM_MUX
(
"MIC1LP P-Terminal"
,
SND_SOC_NOPM
,
0
,
0
,
&
p_term_mic1lp
),
SND_SOC_DAPM_MUX
(
"MIC1RP P-Terminal"
,
SND_SOC_NOPM
,
0
,
0
,
&
p_term_mic1rp
),
SND_SOC_DAPM_MUX
(
"MIC1LM P-Terminal"
,
SND_SOC_NOPM
,
0
,
0
,
&
p_term_mic1lm
),
SND_SOC_DAPM_MUX
(
"MIC1LM M-Terminal"
,
SND_SOC_NOPM
,
0
,
0
,
&
m_term_mic1lm
),
/* Enabling & Disabling MIC Gain Ctl */
SND_SOC_DAPM_PGA
(
"MIC_GAIN_CTL"
,
AIC31XX_MICPGA
,
7
,
1
,
NULL
,
0
),
/* Mic Bias */
SND_SOC_DAPM_SUPPLY
(
"MICBIAS"
,
SND_SOC_NOPM
,
0
,
0
,
mic_bias_event
,
SND_SOC_DAPM_POST_PMU
|
SND_SOC_DAPM_PRE_PMD
),
/* Outputs */
SND_SOC_DAPM_OUTPUT
(
"HPL"
),
SND_SOC_DAPM_OUTPUT
(
"HPR"
),
/* Inputs */
SND_SOC_DAPM_INPUT
(
"MIC1LP"
),
SND_SOC_DAPM_INPUT
(
"MIC1RP"
),
SND_SOC_DAPM_INPUT
(
"MIC1LM"
),
};
static
const
struct
snd_soc_dapm_widget
aic311x_dapm_widgets
[]
=
{
/* AIC3111 and AIC3110 have stereo class-D amplifier */
SND_SOC_DAPM_OUT_DRV_E
(
"SPL ClassD"
,
AIC31XX_SPKAMP
,
7
,
0
,
NULL
,
0
,
aic31xx_dapm_power_event
,
SND_SOC_DAPM_POST_PMU
|
SND_SOC_DAPM_POST_PMD
),
SND_SOC_DAPM_OUT_DRV_E
(
"SPR ClassD"
,
AIC31XX_SPKAMP
,
6
,
0
,
NULL
,
0
,
aic31xx_dapm_power_event
,
SND_SOC_DAPM_POST_PMU
|
SND_SOC_DAPM_POST_PMD
),
SND_SOC_DAPM_SWITCH
(
"Speaker Left"
,
SND_SOC_NOPM
,
0
,
0
,
&
aic31xx_dapm_spl_switch
),
SND_SOC_DAPM_SWITCH
(
"Speaker Right"
,
SND_SOC_NOPM
,
0
,
0
,
&
aic31xx_dapm_spr_switch
),
SND_SOC_DAPM_OUTPUT
(
"SPL"
),
SND_SOC_DAPM_OUTPUT
(
"SPR"
),
};
/* AIC3100 and AIC3120 have only mono class-D amplifier */
static
const
struct
snd_soc_dapm_widget
aic310x_dapm_widgets
[]
=
{
SND_SOC_DAPM_OUT_DRV_E
(
"SPK ClassD"
,
AIC31XX_SPKAMP
,
7
,
0
,
NULL
,
0
,
aic31xx_dapm_power_event
,
SND_SOC_DAPM_POST_PMU
|
SND_SOC_DAPM_POST_PMD
),
SND_SOC_DAPM_SWITCH
(
"Speaker"
,
SND_SOC_NOPM
,
0
,
0
,
&
aic31xx_dapm_spl_switch
),
SND_SOC_DAPM_OUTPUT
(
"SPK"
),
};
static
const
struct
snd_soc_dapm_route
aic31xx_audio_map
[]
=
{
/* DAC Input Routing */
{
"DAC Left Input"
,
"Left Data"
,
"DAC IN"
},
{
"DAC Left Input"
,
"Right Data"
,
"DAC IN"
},
{
"DAC Left Input"
,
"Mono"
,
"DAC IN"
},
{
"DAC Right Input"
,
"Left Data"
,
"DAC IN"
},
{
"DAC Right Input"
,
"Right Data"
,
"DAC IN"
},
{
"DAC Right Input"
,
"Mono"
,
"DAC IN"
},
{
"DAC Left"
,
NULL
,
"DAC Left Input"
},
{
"DAC Right"
,
NULL
,
"DAC Right Input"
},
/* Mic input */
{
"MIC1LP P-Terminal"
,
"FFR 10 Ohm"
,
"MIC1LP"
},
{
"MIC1LP P-Terminal"
,
"FFR 20 Ohm"
,
"MIC1LP"
},
{
"MIC1LP P-Terminal"
,
"FFR 40 Ohm"
,
"MIC1LP"
},
{
"MIC1RP P-Terminal"
,
"FFR 10 Ohm"
,
"MIC1RP"
},
{
"MIC1RP P-Terminal"
,
"FFR 20 Ohm"
,
"MIC1RP"
},
{
"MIC1RP P-Terminal"
,
"FFR 40 Ohm"
,
"MIC1RP"
},
{
"MIC1LM P-Terminal"
,
"FFR 10 Ohm"
,
"MIC1LM"
},
{
"MIC1LM P-Terminal"
,
"FFR 20 Ohm"
,
"MIC1LM"
},
{
"MIC1LM P-Terminal"
,
"FFR 40 Ohm"
,
"MIC1LM"
},
{
"MIC1LM M-Terminal"
,
"FFR 10 Ohm"
,
"MIC1LM"
},
{
"MIC1LM M-Terminal"
,
"FFR 20 Ohm"
,
"MIC1LM"
},
{
"MIC1LM M-Terminal"
,
"FFR 40 Ohm"
,
"MIC1LM"
},
{
"MIC_GAIN_CTL"
,
NULL
,
"MIC1LP P-Terminal"
},
{
"MIC_GAIN_CTL"
,
NULL
,
"MIC1RP P-Terminal"
},
{
"MIC_GAIN_CTL"
,
NULL
,
"MIC1LM P-Terminal"
},
{
"MIC_GAIN_CTL"
,
NULL
,
"MIC1LM M-Terminal"
},
{
"ADC"
,
NULL
,
"MIC_GAIN_CTL"
},
/* Left Output */
{
"Output Left"
,
"From Left DAC"
,
"DAC Left"
},
{
"Output Left"
,
"From MIC1LP"
,
"MIC1LP"
},
{
"Output Left"
,
"From MIC1RP"
,
"MIC1RP"
},
/* Right Output */
{
"Output Right"
,
"From Right DAC"
,
"DAC Right"
},
{
"Output Right"
,
"From MIC1RP"
,
"MIC1RP"
},
/* HPL path */
{
"HP Left"
,
"Switch"
,
"Output Left"
},
{
"HPL Driver"
,
NULL
,
"HP Left"
},
{
"HPL"
,
NULL
,
"HPL Driver"
},
/* HPR path */
{
"HP Right"
,
"Switch"
,
"Output Right"
},
{
"HPR Driver"
,
NULL
,
"HP Right"
},
{
"HPR"
,
NULL
,
"HPR Driver"
},
};
static
const
struct
snd_soc_dapm_route
aic311x_audio_map
[]
=
{
/* SP L path */
{
"Speaker Left"
,
"Switch"
,
"Output Left"
},
{
"SPL ClassD"
,
NULL
,
"Speaker Left"
},
{
"SPL"
,
NULL
,
"SPL ClassD"
},
/* SP R path */
{
"Speaker Right"
,
"Switch"
,
"Output Right"
},
{
"SPR ClassD"
,
NULL
,
"Speaker Right"
},
{
"SPR"
,
NULL
,
"SPR ClassD"
},
};
static
const
struct
snd_soc_dapm_route
aic310x_audio_map
[]
=
{
/* SP L path */
{
"Speaker"
,
"Switch"
,
"Output Left"
},
{
"SPK ClassD"
,
NULL
,
"Speaker"
},
{
"SPK"
,
NULL
,
"SPK ClassD"
},
};
static
int
aic31xx_add_controls
(
struct
snd_soc_codec
*
codec
)
{
int
ret
=
0
;
struct
aic31xx_priv
*
aic31xx
=
snd_soc_codec_get_drvdata
(
codec
);
if
(
aic31xx
->
pdata
.
codec_type
&
AIC31XX_STEREO_CLASS_D_BIT
)
ret
=
snd_soc_add_codec_controls
(
codec
,
aic311x_snd_controls
,
ARRAY_SIZE
(
aic311x_snd_controls
));
else
ret
=
snd_soc_add_codec_controls
(
codec
,
aic310x_snd_controls
,
ARRAY_SIZE
(
aic310x_snd_controls
));
return
ret
;
}
static
int
aic31xx_add_widgets
(
struct
snd_soc_codec
*
codec
)
{
struct
snd_soc_dapm_context
*
dapm
=
&
codec
->
dapm
;
struct
aic31xx_priv
*
aic31xx
=
snd_soc_codec_get_drvdata
(
codec
);
int
ret
=
0
;
if
(
aic31xx
->
pdata
.
codec_type
&
AIC31XX_STEREO_CLASS_D_BIT
)
{
ret
=
snd_soc_dapm_new_controls
(
dapm
,
aic311x_dapm_widgets
,
ARRAY_SIZE
(
aic311x_dapm_widgets
));
if
(
ret
)
return
ret
;
ret
=
snd_soc_dapm_add_routes
(
dapm
,
aic311x_audio_map
,
ARRAY_SIZE
(
aic311x_audio_map
));
if
(
ret
)
return
ret
;
}
else
{
ret
=
snd_soc_dapm_new_controls
(
dapm
,
aic310x_dapm_widgets
,
ARRAY_SIZE
(
aic310x_dapm_widgets
));
if
(
ret
)
return
ret
;
ret
=
snd_soc_dapm_add_routes
(
dapm
,
aic310x_audio_map
,
ARRAY_SIZE
(
aic310x_audio_map
));
if
(
ret
)
return
ret
;
}
return
0
;
}
static
int
aic31xx_setup_pll
(
struct
snd_soc_codec
*
codec
,
struct
snd_pcm_hw_params
*
params
)
{
struct
aic31xx_priv
*
aic31xx
=
snd_soc_codec_get_drvdata
(
codec
);
int
bclk_n
=
0
;
int
i
;
/* Use PLL as CODEC_CLKIN and DAC_CLK as BDIV_CLKIN */
snd_soc_update_bits
(
codec
,
AIC31XX_CLKMUX
,
AIC31XX_CODEC_CLKIN_MASK
,
AIC31XX_CODEC_CLKIN_PLL
);
snd_soc_update_bits
(
codec
,
AIC31XX_IFACE2
,
AIC31XX_BDIVCLK_MASK
,
AIC31XX_DAC2BCLK
);
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
aic31xx_divs
);
i
++
)
{
if
(
aic31xx_divs
[
i
].
rate
==
params_rate
(
params
)
&&
aic31xx_divs
[
i
].
mclk
==
aic31xx
->
sysclk
)
break
;
}
if
(
i
==
ARRAY_SIZE
(
aic31xx_divs
))
{
dev_err
(
codec
->
dev
,
"%s: Sampling rate %u not supported
\n
"
,
__func__
,
params_rate
(
params
));
return
-
EINVAL
;
}
/* PLL configuration */
snd_soc_update_bits
(
codec
,
AIC31XX_PLLPR
,
AIC31XX_PLL_MASK
,
(
aic31xx_divs
[
i
].
p_val
<<
4
)
|
0x01
);
snd_soc_write
(
codec
,
AIC31XX_PLLJ
,
aic31xx_divs
[
i
].
pll_j
);
snd_soc_write
(
codec
,
AIC31XX_PLLDMSB
,
aic31xx_divs
[
i
].
pll_d
>>
8
);
snd_soc_write
(
codec
,
AIC31XX_PLLDLSB
,
aic31xx_divs
[
i
].
pll_d
&
0xff
);
/* DAC dividers configuration */
snd_soc_update_bits
(
codec
,
AIC31XX_NDAC
,
AIC31XX_PLL_MASK
,
aic31xx_divs
[
i
].
ndac
);
snd_soc_update_bits
(
codec
,
AIC31XX_MDAC
,
AIC31XX_PLL_MASK
,
aic31xx_divs
[
i
].
mdac
);
snd_soc_write
(
codec
,
AIC31XX_DOSRMSB
,
aic31xx_divs
[
i
].
dosr
>>
8
);
snd_soc_write
(
codec
,
AIC31XX_DOSRLSB
,
aic31xx_divs
[
i
].
dosr
&
0xff
);
/* ADC dividers configuration. Write reset value 1 if not used. */
snd_soc_update_bits
(
codec
,
AIC31XX_NADC
,
AIC31XX_PLL_MASK
,
aic31xx_divs
[
i
].
nadc
?
aic31xx_divs
[
i
].
nadc
:
1
);
snd_soc_update_bits
(
codec
,
AIC31XX_MADC
,
AIC31XX_PLL_MASK
,
aic31xx_divs
[
i
].
madc
?
aic31xx_divs
[
i
].
madc
:
1
);
snd_soc_write
(
codec
,
AIC31XX_AOSR
,
aic31xx_divs
[
i
].
aosr
);
/* Bit clock divider configuration. */
bclk_n
=
(
aic31xx_divs
[
i
].
dosr
*
aic31xx_divs
[
i
].
mdac
)
/
snd_soc_params_to_frame_size
(
params
);
if
(
bclk_n
==
0
)
{
dev_err
(
codec
->
dev
,
"%s: Not enough BLCK bandwidth
\n
"
,
__func__
);
return
-
EINVAL
;
}
snd_soc_update_bits
(
codec
,
AIC31XX_BCLKN
,
AIC31XX_PLL_MASK
,
bclk_n
);
aic31xx
->
rate_div_line
=
i
;
dev_dbg
(
codec
->
dev
,
"pll %d.%04d/%d dosr %d n %d m %d aosr %d n %d m %d bclk_n %d
\n
"
,
aic31xx_divs
[
i
].
pll_j
,
aic31xx_divs
[
i
].
pll_d
,
aic31xx_divs
[
i
].
p_val
,
aic31xx_divs
[
i
].
dosr
,
aic31xx_divs
[
i
].
ndac
,
aic31xx_divs
[
i
].
mdac
,
aic31xx_divs
[
i
].
aosr
,
aic31xx_divs
[
i
].
nadc
,
aic31xx_divs
[
i
].
madc
,
bclk_n
);
return
0
;
}
static
int
aic31xx_hw_params
(
struct
snd_pcm_substream
*
substream
,
struct
snd_pcm_hw_params
*
params
,
struct
snd_soc_dai
*
tmp
)
{
struct
snd_soc_pcm_runtime
*
rtd
=
substream
->
private_data
;
struct
snd_soc_codec
*
codec
=
rtd
->
codec
;
u8
data
=
0
;
dev_dbg
(
codec
->
dev
,
"## %s: format %d width %d rate %d
\n
"
,
__func__
,
params_format
(
params
),
params_width
(
params
),
params_rate
(
params
));
switch
(
params_width
(
params
))
{
case
16
:
break
;
case
20
:
data
=
(
AIC31XX_WORD_LEN_20BITS
<<
AIC31XX_IFACE1_DATALEN_SHIFT
);
break
;
case
24
:
data
=
(
AIC31XX_WORD_LEN_24BITS
<<
AIC31XX_IFACE1_DATALEN_SHIFT
);
break
;
case
32
:
data
=
(
AIC31XX_WORD_LEN_32BITS
<<
AIC31XX_IFACE1_DATALEN_SHIFT
);
break
;
default:
dev_err
(
codec
->
dev
,
"%s: Unsupported format %d
\n
"
,
__func__
,
params_format
(
params
));
return
-
EINVAL
;
}
snd_soc_update_bits
(
codec
,
AIC31XX_IFACE1
,
AIC31XX_IFACE1_DATALEN_MASK
,
data
);
return
aic31xx_setup_pll
(
codec
,
params
);
}
static
int
aic31xx_dac_mute
(
struct
snd_soc_dai
*
codec_dai
,
int
mute
)
{
struct
snd_soc_codec
*
codec
=
codec_dai
->
codec
;
if
(
mute
)
{
snd_soc_update_bits
(
codec
,
AIC31XX_DACMUTE
,
AIC31XX_DACMUTE_MASK
,
AIC31XX_DACMUTE_MASK
);
}
else
{
snd_soc_update_bits
(
codec
,
AIC31XX_DACMUTE
,
AIC31XX_DACMUTE_MASK
,
0x0
);
}
return
0
;
}
static
int
aic31xx_set_dai_fmt
(
struct
snd_soc_dai
*
codec_dai
,
unsigned
int
fmt
)
{
struct
snd_soc_codec
*
codec
=
codec_dai
->
codec
;
u8
iface_reg1
=
0
;
u8
iface_reg3
=
0
;
u8
dsp_a_val
=
0
;
dev_dbg
(
codec
->
dev
,
"## %s: fmt = 0x%x
\n
"
,
__func__
,
fmt
);
/* set master/slave audio interface */
switch
(
fmt
&
SND_SOC_DAIFMT_MASTER_MASK
)
{
case
SND_SOC_DAIFMT_CBM_CFM
:
iface_reg1
|=
AIC31XX_BCLK_MASTER
|
AIC31XX_WCLK_MASTER
;
break
;
default:
dev_alert
(
codec
->
dev
,
"Invalid DAI master/slave interface
\n
"
);
return
-
EINVAL
;
}
/* interface format */
switch
(
fmt
&
SND_SOC_DAIFMT_FORMAT_MASK
)
{
case
SND_SOC_DAIFMT_I2S
:
break
;
case
SND_SOC_DAIFMT_DSP_A
:
dsp_a_val
=
0x1
;
case
SND_SOC_DAIFMT_DSP_B
:
/* NOTE: BCLKINV bit value 1 equas NB and 0 equals IB */
switch
(
fmt
&
SND_SOC_DAIFMT_INV_MASK
)
{
case
SND_SOC_DAIFMT_NB_NF
:
iface_reg3
|=
AIC31XX_BCLKINV_MASK
;
break
;
case
SND_SOC_DAIFMT_IB_NF
:
break
;
default:
return
-
EINVAL
;
}
iface_reg1
|=
(
AIC31XX_DSP_MODE
<<
AIC31XX_IFACE1_DATATYPE_SHIFT
);
break
;
case
SND_SOC_DAIFMT_RIGHT_J
:
iface_reg1
|=
(
AIC31XX_RIGHT_JUSTIFIED_MODE
<<
AIC31XX_IFACE1_DATATYPE_SHIFT
);
break
;
case
SND_SOC_DAIFMT_LEFT_J
:
iface_reg1
|=
(
AIC31XX_LEFT_JUSTIFIED_MODE
<<
AIC31XX_IFACE1_DATATYPE_SHIFT
);
break
;
default:
dev_err
(
codec
->
dev
,
"Invalid DAI interface format
\n
"
);
return
-
EINVAL
;
}
snd_soc_update_bits
(
codec
,
AIC31XX_IFACE1
,
AIC31XX_IFACE1_DATATYPE_MASK
|
AIC31XX_IFACE1_MASTER_MASK
,
iface_reg1
);
snd_soc_update_bits
(
codec
,
AIC31XX_DATA_OFFSET
,
AIC31XX_DATA_OFFSET_MASK
,
dsp_a_val
);
snd_soc_update_bits
(
codec
,
AIC31XX_IFACE2
,
AIC31XX_BCLKINV_MASK
,
iface_reg3
);
return
0
;
}
static
int
aic31xx_set_dai_sysclk
(
struct
snd_soc_dai
*
codec_dai
,
int
clk_id
,
unsigned
int
freq
,
int
dir
)
{
struct
snd_soc_codec
*
codec
=
codec_dai
->
codec
;
struct
aic31xx_priv
*
aic31xx
=
snd_soc_codec_get_drvdata
(
codec
);
int
i
;
dev_dbg
(
codec
->
dev
,
"## %s: clk_id = %d, freq = %d, dir = %d
\n
"
,
__func__
,
clk_id
,
freq
,
dir
);
for
(
i
=
0
;
aic31xx_divs
[
i
].
mclk
!=
freq
;
i
++
)
{
if
(
i
==
ARRAY_SIZE
(
aic31xx_divs
))
{
dev_err
(
aic31xx
->
dev
,
"%s: Unsupported frequency %d
\n
"
,
__func__
,
freq
);
return
-
EINVAL
;
}
}
/* set clock on MCLK, BCLK, or GPIO1 as PLL input */
snd_soc_update_bits
(
codec
,
AIC31XX_CLKMUX
,
AIC31XX_PLL_CLKIN_MASK
,
clk_id
<<
AIC31XX_PLL_CLKIN_SHIFT
);
aic31xx
->
sysclk
=
freq
;
return
0
;
}
static
int
aic31xx_regulator_event
(
struct
notifier_block
*
nb
,
unsigned
long
event
,
void
*
data
)
{
struct
aic31xx_disable_nb
*
disable_nb
=
container_of
(
nb
,
struct
aic31xx_disable_nb
,
nb
);
struct
aic31xx_priv
*
aic31xx
=
disable_nb
->
aic31xx
;
if
(
event
&
REGULATOR_EVENT_DISABLE
)
{
/*
* Put codec to reset and as at least one of the
* supplies was disabled.
*/
if
(
gpio_is_valid
(
aic31xx
->
pdata
.
gpio_reset
))
gpio_set_value
(
aic31xx
->
pdata
.
gpio_reset
,
0
);
regcache_mark_dirty
(
aic31xx
->
regmap
);
dev_dbg
(
aic31xx
->
dev
,
"## %s: DISABLE received
\n
"
,
__func__
);
}
return
0
;
}
static
void
aic31xx_clk_on
(
struct
snd_soc_codec
*
codec
)
{
struct
aic31xx_priv
*
aic31xx
=
snd_soc_codec_get_drvdata
(
codec
);
u8
mask
=
AIC31XX_PM_MASK
;
u8
on
=
AIC31XX_PM_MASK
;
dev_dbg
(
codec
->
dev
,
"codec clock -> on (rate %d)
\n
"
,
aic31xx_divs
[
aic31xx
->
rate_div_line
].
rate
);
snd_soc_update_bits
(
codec
,
AIC31XX_PLLPR
,
mask
,
on
);
mdelay
(
10
);
snd_soc_update_bits
(
codec
,
AIC31XX_NDAC
,
mask
,
on
);
snd_soc_update_bits
(
codec
,
AIC31XX_MDAC
,
mask
,
on
);
if
(
aic31xx_divs
[
aic31xx
->
rate_div_line
].
nadc
)
snd_soc_update_bits
(
codec
,
AIC31XX_NADC
,
mask
,
on
);
if
(
aic31xx_divs
[
aic31xx
->
rate_div_line
].
madc
)
snd_soc_update_bits
(
codec
,
AIC31XX_MADC
,
mask
,
on
);
snd_soc_update_bits
(
codec
,
AIC31XX_BCLKN
,
mask
,
on
);
}
static
void
aic31xx_clk_off
(
struct
snd_soc_codec
*
codec
)
{
struct
aic31xx_priv
*
aic31xx
=
snd_soc_codec_get_drvdata
(
codec
);
u8
mask
=
AIC31XX_PM_MASK
;
u8
off
=
0
;
dev_dbg
(
codec
->
dev
,
"codec clock -> off
\n
"
);
snd_soc_update_bits
(
codec
,
AIC31XX_BCLKN
,
mask
,
off
);
snd_soc_update_bits
(
codec
,
AIC31XX_MADC
,
mask
,
off
);
snd_soc_update_bits
(
codec
,
AIC31XX_NADC
,
mask
,
off
);
snd_soc_update_bits
(
codec
,
AIC31XX_MDAC
,
mask
,
off
);
snd_soc_update_bits
(
codec
,
AIC31XX_NDAC
,
mask
,
off
);
snd_soc_update_bits
(
codec
,
AIC31XX_PLLPR
,
mask
,
off
);
}
static
int
aic31xx_power_on
(
struct
snd_soc_codec
*
codec
)
{
struct
aic31xx_priv
*
aic31xx
=
snd_soc_codec_get_drvdata
(
codec
);
int
ret
=
0
;
ret
=
regulator_bulk_enable
(
ARRAY_SIZE
(
aic31xx
->
supplies
),
aic31xx
->
supplies
);
if
(
ret
)
return
ret
;
if
(
gpio_is_valid
(
aic31xx
->
pdata
.
gpio_reset
))
{
gpio_set_value
(
aic31xx
->
pdata
.
gpio_reset
,
1
);
udelay
(
100
);
}
regcache_cache_only
(
aic31xx
->
regmap
,
false
);
ret
=
regcache_sync
(
aic31xx
->
regmap
);
if
(
ret
!=
0
)
{
dev_err
(
codec
->
dev
,
"Failed to restore cache: %d
\n
"
,
ret
);
regcache_cache_only
(
aic31xx
->
regmap
,
true
);
regulator_bulk_disable
(
ARRAY_SIZE
(
aic31xx
->
supplies
),
aic31xx
->
supplies
);
return
ret
;
}
return
0
;
}
static
int
aic31xx_power_off
(
struct
snd_soc_codec
*
codec
)
{
struct
aic31xx_priv
*
aic31xx
=
snd_soc_codec_get_drvdata
(
codec
);
int
ret
=
0
;
regcache_cache_only
(
aic31xx
->
regmap
,
true
);
ret
=
regulator_bulk_disable
(
ARRAY_SIZE
(
aic31xx
->
supplies
),
aic31xx
->
supplies
);
return
ret
;
}
static
int
aic31xx_set_bias_level
(
struct
snd_soc_codec
*
codec
,
enum
snd_soc_bias_level
level
)
{
dev_dbg
(
codec
->
dev
,
"## %s: %d -> %d
\n
"
,
__func__
,
codec
->
dapm
.
bias_level
,
level
);
switch
(
level
)
{
case
SND_SOC_BIAS_ON
:
break
;
case
SND_SOC_BIAS_PREPARE
:
if
(
codec
->
dapm
.
bias_level
==
SND_SOC_BIAS_STANDBY
)
aic31xx_clk_on
(
codec
);
break
;
case
SND_SOC_BIAS_STANDBY
:
switch
(
codec
->
dapm
.
bias_level
)
{
case
SND_SOC_BIAS_OFF
:
aic31xx_power_on
(
codec
);
break
;
case
SND_SOC_BIAS_PREPARE
:
aic31xx_clk_off
(
codec
);
break
;
default:
BUG
();
}
break
;
case
SND_SOC_BIAS_OFF
:
aic31xx_power_off
(
codec
);
break
;
}
codec
->
dapm
.
bias_level
=
level
;
return
0
;
}
static
int
aic31xx_suspend
(
struct
snd_soc_codec
*
codec
)
{
aic31xx_set_bias_level
(
codec
,
SND_SOC_BIAS_OFF
);
return
0
;
}
static
int
aic31xx_resume
(
struct
snd_soc_codec
*
codec
)
{
aic31xx_set_bias_level
(
codec
,
SND_SOC_BIAS_STANDBY
);
return
0
;
}
static
int
aic31xx_codec_probe
(
struct
snd_soc_codec
*
codec
)
{
int
ret
=
0
;
struct
aic31xx_priv
*
aic31xx
=
snd_soc_codec_get_drvdata
(
codec
);
int
i
;
dev_dbg
(
aic31xx
->
dev
,
"## %s
\n
"
,
__func__
);
aic31xx
=
snd_soc_codec_get_drvdata
(
codec
);
codec
->
control_data
=
aic31xx
->
regmap
;
aic31xx
->
codec
=
codec
;
ret
=
snd_soc_codec_set_cache_io
(
codec
,
8
,
8
,
SND_SOC_REGMAP
);
if
(
ret
!=
0
)
{
dev_err
(
codec
->
dev
,
"snd_soc_codec_set_cache_io failed %d
\n
"
,
ret
);
return
ret
;
}
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
aic31xx
->
supplies
);
i
++
)
{
aic31xx
->
disable_nb
[
i
].
nb
.
notifier_call
=
aic31xx_regulator_event
;
aic31xx
->
disable_nb
[
i
].
aic31xx
=
aic31xx
;
ret
=
regulator_register_notifier
(
aic31xx
->
supplies
[
i
].
consumer
,
&
aic31xx
->
disable_nb
[
i
].
nb
);
if
(
ret
)
{
dev_err
(
codec
->
dev
,
"Failed to request regulator notifier: %d
\n
"
,
ret
);
return
ret
;
}
}
regcache_cache_only
(
aic31xx
->
regmap
,
true
);
regcache_mark_dirty
(
aic31xx
->
regmap
);
ret
=
aic31xx_add_controls
(
codec
);
if
(
ret
)
return
ret
;
ret
=
aic31xx_add_widgets
(
codec
);
return
ret
;
}
static
int
aic31xx_codec_remove
(
struct
snd_soc_codec
*
codec
)
{
struct
aic31xx_priv
*
aic31xx
=
snd_soc_codec_get_drvdata
(
codec
);
int
i
;
/* power down chip */
aic31xx_set_bias_level
(
codec
,
SND_SOC_BIAS_OFF
);
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
aic31xx
->
supplies
);
i
++
)
regulator_unregister_notifier
(
aic31xx
->
supplies
[
i
].
consumer
,
&
aic31xx
->
disable_nb
[
i
].
nb
);
return
0
;
}
static
struct
snd_soc_codec_driver
soc_codec_driver_aic31xx
=
{
.
probe
=
aic31xx_codec_probe
,
.
remove
=
aic31xx_codec_remove
,
.
suspend
=
aic31xx_suspend
,
.
resume
=
aic31xx_resume
,
.
set_bias_level
=
aic31xx_set_bias_level
,
.
controls
=
aic31xx_snd_controls
,
.
num_controls
=
ARRAY_SIZE
(
aic31xx_snd_controls
),
.
dapm_widgets
=
aic31xx_dapm_widgets
,
.
num_dapm_widgets
=
ARRAY_SIZE
(
aic31xx_dapm_widgets
),
.
dapm_routes
=
aic31xx_audio_map
,
.
num_dapm_routes
=
ARRAY_SIZE
(
aic31xx_audio_map
),
};
static
struct
snd_soc_dai_ops
aic31xx_dai_ops
=
{
.
hw_params
=
aic31xx_hw_params
,
.
set_sysclk
=
aic31xx_set_dai_sysclk
,
.
set_fmt
=
aic31xx_set_dai_fmt
,
.
digital_mute
=
aic31xx_dac_mute
,
};
static
struct
snd_soc_dai_driver
aic31xx_dai_driver
[]
=
{
{
.
name
=
"tlv320aic31xx-hifi"
,
.
playback
=
{
.
stream_name
=
"Playback"
,
.
channels_min
=
1
,
.
channels_max
=
2
,
.
rates
=
AIC31XX_RATES
,
.
formats
=
AIC31XX_FORMATS
,
},
.
capture
=
{
.
stream_name
=
"Capture"
,
.
channels_min
=
1
,
.
channels_max
=
2
,
.
rates
=
AIC31XX_RATES
,
.
formats
=
AIC31XX_FORMATS
,
},
.
ops
=
&
aic31xx_dai_ops
,
.
symmetric_rates
=
1
,
}
};
#if defined(CONFIG_OF)
static
const
struct
of_device_id
tlv320aic31xx_of_match
[]
=
{
{
.
compatible
=
"ti,tlv320aic310x"
},
{
.
compatible
=
"ti,tlv320aic311x"
},
{
.
compatible
=
"ti,tlv320aic3100"
},
{
.
compatible
=
"ti,tlv320aic3110"
},
{
.
compatible
=
"ti,tlv320aic3120"
},
{
.
compatible
=
"ti,tlv320aic3111"
},
{},
};
MODULE_DEVICE_TABLE
(
of
,
tlv320aic31xx_of_match
);
static
void
aic31xx_pdata_from_of
(
struct
aic31xx_priv
*
aic31xx
)
{
struct
device_node
*
np
=
aic31xx
->
dev
->
of_node
;
unsigned
int
value
=
MICBIAS_2_0V
;
int
ret
;
of_property_read_u32
(
np
,
"ai31xx-micbias-vg"
,
&
value
);
switch
(
value
)
{
case
MICBIAS_2_0V
:
case
MICBIAS_2_5V
:
case
MICBIAS_AVDDV
:
aic31xx
->
pdata
.
micbias_vg
=
value
;
break
;
default:
dev_err
(
aic31xx
->
dev
,
"Bad ai31xx-micbias-vg value %d DT
\n
"
,
value
);
aic31xx
->
pdata
.
micbias_vg
=
MICBIAS_2_0V
;
}
ret
=
of_get_named_gpio
(
np
,
"gpio-reset"
,
0
);
if
(
ret
>
0
)
aic31xx
->
pdata
.
gpio_reset
=
ret
;
}
#else
/* CONFIG_OF */
static
void
aic31xx_pdata_from_of
(
struct
aic31xx_priv
*
aic31xx
)
{
}
#endif
/* CONFIG_OF */
void
aic31xx_device_init
(
struct
aic31xx_priv
*
aic31xx
)
{
int
ret
,
i
;
dev_set_drvdata
(
aic31xx
->
dev
,
aic31xx
);
if
(
dev_get_platdata
(
aic31xx
->
dev
))
memcpy
(
&
aic31xx
->
pdata
,
dev_get_platdata
(
aic31xx
->
dev
),
sizeof
(
aic31xx
->
pdata
));
else
if
(
aic31xx
->
dev
->
of_node
)
aic31xx_pdata_from_of
(
aic31xx
);
if
(
aic31xx
->
pdata
.
gpio_reset
)
{
ret
=
devm_gpio_request_one
(
aic31xx
->
dev
,
aic31xx
->
pdata
.
gpio_reset
,
GPIOF_OUT_INIT_HIGH
,
"aic31xx-reset-pin"
);
if
(
ret
<
0
)
{
dev_err
(
aic31xx
->
dev
,
"not able to acquire gpio
\n
"
);
return
;
}
}
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
aic31xx
->
supplies
);
i
++
)
aic31xx
->
supplies
[
i
].
supply
=
aic31xx_supply_names
[
i
];
ret
=
devm_regulator_bulk_get
(
aic31xx
->
dev
,
ARRAY_SIZE
(
aic31xx
->
supplies
),
aic31xx
->
supplies
);
if
(
ret
!=
0
)
dev_err
(
aic31xx
->
dev
,
"Failed to request supplies: %d
\n
"
,
ret
);
}
static
int
aic31xx_i2c_probe
(
struct
i2c_client
*
i2c
,
const
struct
i2c_device_id
*
id
)
{
struct
aic31xx_priv
*
aic31xx
;
int
ret
;
const
struct
regmap_config
*
regmap_config
;
dev_dbg
(
&
i2c
->
dev
,
"## %s: %s codec_type = %d
\n
"
,
__func__
,
id
->
name
,
(
int
)
id
->
driver_data
);
regmap_config
=
&
aic31xx_i2c_regmap
;
aic31xx
=
devm_kzalloc
(
&
i2c
->
dev
,
sizeof
(
*
aic31xx
),
GFP_KERNEL
);
if
(
aic31xx
==
NULL
)
return
-
ENOMEM
;
aic31xx
->
regmap
=
devm_regmap_init_i2c
(
i2c
,
regmap_config
);
if
(
IS_ERR
(
aic31xx
->
regmap
))
{
ret
=
PTR_ERR
(
aic31xx
->
regmap
);
dev_err
(
&
i2c
->
dev
,
"Failed to allocate register map: %d
\n
"
,
ret
);
return
ret
;
}
aic31xx
->
dev
=
&
i2c
->
dev
;
aic31xx
->
pdata
.
codec_type
=
id
->
driver_data
;
aic31xx_device_init
(
aic31xx
);
ret
=
snd_soc_register_codec
(
&
i2c
->
dev
,
&
soc_codec_driver_aic31xx
,
aic31xx_dai_driver
,
ARRAY_SIZE
(
aic31xx_dai_driver
));
return
ret
;
}
static
int
aic31xx_i2c_remove
(
struct
i2c_client
*
i2c
)
{
struct
aic31xx_priv
*
aic31xx
=
dev_get_drvdata
(
&
i2c
->
dev
);
kfree
(
aic31xx
);
return
0
;
}
static
const
struct
i2c_device_id
aic31xx_i2c_id
[]
=
{
{
"tlv320aic310x"
,
AIC3100
},
{
"tlv320aic311x"
,
AIC3110
},
{
"tlv320aic3100"
,
AIC3100
},
{
"tlv320aic3110"
,
AIC3110
},
{
"tlv320aic3120"
,
AIC3120
},
{
"tlv320aic3111"
,
AIC3111
},
{
}
};
MODULE_DEVICE_TABLE
(
i2c
,
aic31xx_i2c_id
);
static
struct
i2c_driver
aic31xx_i2c_driver
=
{
.
driver
=
{
.
name
=
"tlv320aic31xx-codec"
,
.
owner
=
THIS_MODULE
,
.
of_match_table
=
of_match_ptr
(
tlv320aic31xx_of_match
),
},
.
probe
=
aic31xx_i2c_probe
,
.
remove
=
(
aic31xx_i2c_remove
),
.
id_table
=
aic31xx_i2c_id
,
};
module_i2c_driver
(
aic31xx_i2c_driver
);
MODULE_DESCRIPTION
(
"ASoC TLV320AIC3111 codec driver"
);
MODULE_AUTHOR
(
"Jyri Sarha"
);
MODULE_LICENSE
(
"GPL"
);
sound/soc/codecs/tlv320aic31xx.h
0 → 100644
View file @
56fe4897
/*
* ALSA SoC TLV320AIC31XX codec driver
*
* Copyright (C) 2013 Texas Instruments, Inc.
*
* This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
*/
#ifndef _TLV320AIC31XX_H
#define _TLV320AIC31XX_H
#define AIC31XX_RATES SNDRV_PCM_RATE_8000_192000
#define AIC31XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
| SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
#define AIC31XX_STEREO_CLASS_D_BIT 0x1
#define AIC31XX_MINIDSP_BIT 0x2
enum
aic31xx_type
{
AIC3100
=
0
,
AIC3110
=
AIC31XX_STEREO_CLASS_D_BIT
,
AIC3120
=
AIC31XX_MINIDSP_BIT
,
AIC3111
=
(
AIC31XX_STEREO_CLASS_D_BIT
|
AIC31XX_MINIDSP_BIT
),
};
struct
aic31xx_pdata
{
enum
aic31xx_type
codec_type
;
unsigned
int
gpio_reset
;
int
micbias_vg
;
};
/* Page Control Register */
#define AIC31XX_PAGECTL 0x00
/* Page 0 Registers */
/* Software reset register */
#define AIC31XX_RESET 0x01
/* OT FLAG register */
#define AIC31XX_OT_FLAG 0x03
/* Clock clock Gen muxing, Multiplexers*/
#define AIC31XX_CLKMUX 0x04
/* PLL P and R-VAL register */
#define AIC31XX_PLLPR 0x05
/* PLL J-VAL register */
#define AIC31XX_PLLJ 0x06
/* PLL D-VAL MSB register */
#define AIC31XX_PLLDMSB 0x07
/* PLL D-VAL LSB register */
#define AIC31XX_PLLDLSB 0x08
/* DAC NDAC_VAL register*/
#define AIC31XX_NDAC 0x0B
/* DAC MDAC_VAL register */
#define AIC31XX_MDAC 0x0C
/* DAC OSR setting register 1, MSB value */
#define AIC31XX_DOSRMSB 0x0D
/* DAC OSR setting register 2, LSB value */
#define AIC31XX_DOSRLSB 0x0E
#define AIC31XX_MINI_DSP_INPOL 0x10
/* Clock setting register 8, PLL */
#define AIC31XX_NADC 0x12
/* Clock setting register 9, PLL */
#define AIC31XX_MADC 0x13
/* ADC Oversampling (AOSR) Register */
#define AIC31XX_AOSR 0x14
/* Clock setting register 9, Multiplexers */
#define AIC31XX_CLKOUTMUX 0x19
/* Clock setting register 10, CLOCKOUT M divider value */
#define AIC31XX_CLKOUTMVAL 0x1A
/* Audio Interface Setting Register 1 */
#define AIC31XX_IFACE1 0x1B
/* Audio Data Slot Offset Programming */
#define AIC31XX_DATA_OFFSET 0x1C
/* Audio Interface Setting Register 2 */
#define AIC31XX_IFACE2 0x1D
/* Clock setting register 11, BCLK N Divider */
#define AIC31XX_BCLKN 0x1E
/* Audio Interface Setting Register 3, Secondary Audio Interface */
#define AIC31XX_IFACESEC1 0x1F
/* Audio Interface Setting Register 4 */
#define AIC31XX_IFACESEC2 0x20
/* Audio Interface Setting Register 5 */
#define AIC31XX_IFACESEC3 0x21
/* I2C Bus Condition */
#define AIC31XX_I2C 0x22
/* ADC FLAG */
#define AIC31XX_ADCFLAG 0x24
/* DAC Flag Registers */
#define AIC31XX_DACFLAG1 0x25
#define AIC31XX_DACFLAG2 0x26
/* Sticky Interrupt flag (overflow) */
#define AIC31XX_OFFLAG 0x27
/* Sticy DAC Interrupt flags */
#define AIC31XX_INTRDACFLAG 0x2C
/* Sticy ADC Interrupt flags */
#define AIC31XX_INTRADCFLAG 0x2D
/* DAC Interrupt flags 2 */
#define AIC31XX_INTRDACFLAG2 0x2E
/* ADC Interrupt flags 2 */
#define AIC31XX_INTRADCFLAG2 0x2F
/* INT1 interrupt control */
#define AIC31XX_INT1CTRL 0x30
/* INT2 interrupt control */
#define AIC31XX_INT2CTRL 0x31
/* GPIO1 control */
#define AIC31XX_GPIO1 0x33
#define AIC31XX_DACPRB 0x3C
/* ADC Instruction Set Register */
#define AIC31XX_ADCPRB 0x3D
/* DAC channel setup register */
#define AIC31XX_DACSETUP 0x3F
/* DAC Mute and volume control register */
#define AIC31XX_DACMUTE 0x40
/* Left DAC channel digital volume control */
#define AIC31XX_LDACVOL 0x41
/* Right DAC channel digital volume control */
#define AIC31XX_RDACVOL 0x42
/* Headset detection */
#define AIC31XX_HSDETECT 0x43
/* ADC Digital Mic */
#define AIC31XX_ADCSETUP 0x51
/* ADC Digital Volume Control Fine Adjust */
#define AIC31XX_ADCFGA 0x52
/* ADC Digital Volume Control Coarse Adjust */
#define AIC31XX_ADCVOL 0x53
/* Page 1 Registers */
/* Headphone drivers */
#define AIC31XX_HPDRIVER 0x9F
/* Class-D Speakear Amplifier */
#define AIC31XX_SPKAMP 0xA0
/* HP Output Drivers POP Removal Settings */
#define AIC31XX_HPPOP 0xA1
/* Output Driver PGA Ramp-Down Period Control */
#define AIC31XX_SPPGARAMP 0xA2
/* DAC_L and DAC_R Output Mixer Routing */
#define AIC31XX_DACMIXERROUTE 0xA3
/* Left Analog Vol to HPL */
#define AIC31XX_LANALOGHPL 0xA4
/* Right Analog Vol to HPR */
#define AIC31XX_RANALOGHPR 0xA5
/* Left Analog Vol to SPL */
#define AIC31XX_LANALOGSPL 0xA6
/* Right Analog Vol to SPR */
#define AIC31XX_RANALOGSPR 0xA7
/* HPL Driver */
#define AIC31XX_HPLGAIN 0xA8
/* HPR Driver */
#define AIC31XX_HPRGAIN 0xA9
/* SPL Driver */
#define AIC31XX_SPLGAIN 0xAA
/* SPR Driver */
#define AIC31XX_SPRGAIN 0xAB
/* HP Driver Control */
#define AIC31XX_HPCONTROL 0xAC
/* MIC Bias Control */
#define AIC31XX_MICBIAS 0xAE
/* MIC PGA*/
#define AIC31XX_MICPGA 0xAF
/* Delta-Sigma Mono ADC Channel Fine-Gain Input Selection for P-Terminal */
#define AIC31XX_MICPGAPI 0xB0
/* ADC Input Selection for M-Terminal */
#define AIC31XX_MICPGAMI 0xB1
/* Input CM Settings */
#define AIC31XX_MICPGACM 0xB2
/* Bits, masks and shifts */
/* AIC31XX_CLKMUX */
#define AIC31XX_PLL_CLKIN_MASK 0x0c
#define AIC31XX_PLL_CLKIN_SHIFT 2
#define AIC31XX_PLL_CLKIN_MCLK 0
#define AIC31XX_CODEC_CLKIN_MASK 0x03
#define AIC31XX_CODEC_CLKIN_SHIFT 0
#define AIC31XX_CODEC_CLKIN_PLL 3
#define AIC31XX_CODEC_CLKIN_BCLK 1
/* AIC31XX_PLLPR, AIC31XX_NDAC, AIC31XX_MDAC, AIC31XX_NADC, AIC31XX_MADC,
AIC31XX_BCLKN */
#define AIC31XX_PLL_MASK 0x7f
#define AIC31XX_PM_MASK 0x80
/* AIC31XX_IFACE1 */
#define AIC31XX_WORD_LEN_16BITS 0x00
#define AIC31XX_WORD_LEN_20BITS 0x01
#define AIC31XX_WORD_LEN_24BITS 0x02
#define AIC31XX_WORD_LEN_32BITS 0x03
#define AIC31XX_IFACE1_DATALEN_MASK 0x30
#define AIC31XX_IFACE1_DATALEN_SHIFT (4)
#define AIC31XX_IFACE1_DATATYPE_MASK 0xC0
#define AIC31XX_IFACE1_DATATYPE_SHIFT (6)
#define AIC31XX_I2S_MODE 0x00
#define AIC31XX_DSP_MODE 0x01
#define AIC31XX_RIGHT_JUSTIFIED_MODE 0x02
#define AIC31XX_LEFT_JUSTIFIED_MODE 0x03
#define AIC31XX_IFACE1_MASTER_MASK 0x0C
#define AIC31XX_BCLK_MASTER 0x08
#define AIC31XX_WCLK_MASTER 0x04
/* AIC31XX_DATA_OFFSET */
#define AIC31XX_DATA_OFFSET_MASK 0xFF
/* AIC31XX_IFACE2 */
#define AIC31XX_BCLKINV_MASK 0x08
#define AIC31XX_BDIVCLK_MASK 0x03
#define AIC31XX_DAC2BCLK 0x00
#define AIC31XX_DACMOD2BCLK 0x01
#define AIC31XX_ADC2BCLK 0x02
#define AIC31XX_ADCMOD2BCLK 0x03
/* AIC31XX_ADCFLAG */
#define AIC31XX_ADCPWRSTATUS_MASK 0x40
/* AIC31XX_DACFLAG1 */
#define AIC31XX_LDACPWRSTATUS_MASK 0x80
#define AIC31XX_RDACPWRSTATUS_MASK 0x08
#define AIC31XX_HPLDRVPWRSTATUS_MASK 0x20
#define AIC31XX_HPRDRVPWRSTATUS_MASK 0x02
#define AIC31XX_SPLDRVPWRSTATUS_MASK 0x10
#define AIC31XX_SPRDRVPWRSTATUS_MASK 0x01
/* AIC31XX_INTRDACFLAG */
#define AIC31XX_HPSCDETECT_MASK 0x80
#define AIC31XX_BUTTONPRESS_MASK 0x20
#define AIC31XX_HSPLUG_MASK 0x10
#define AIC31XX_LDRCTHRES_MASK 0x08
#define AIC31XX_RDRCTHRES_MASK 0x04
#define AIC31XX_DACSINT_MASK 0x02
#define AIC31XX_DACAINT_MASK 0x01
/* AIC31XX_INT1CTRL */
#define AIC31XX_HSPLUGDET_MASK 0x80
#define AIC31XX_BUTTONPRESSDET_MASK 0x40
#define AIC31XX_DRCTHRES_MASK 0x20
#define AIC31XX_AGCNOISE_MASK 0x10
#define AIC31XX_OC_MASK 0x08
#define AIC31XX_ENGINE_MASK 0x04
/* AIC31XX_DACSETUP */
#define AIC31XX_SOFTSTEP_MASK 0x03
/* AIC31XX_DACMUTE */
#define AIC31XX_DACMUTE_MASK 0x0C
/* AIC31XX_MICBIAS */
#define AIC31XX_MICBIAS_MASK 0x03
#define AIC31XX_MICBIAS_SHIFT 0
#endif
/* _TLV320AIC31XX_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