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
0583060f
Commit
0583060f
authored
Jan 12, 2018
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'asoc/topic/pcm186x' into asoc-next
parents
3e4555ab
dce231a4
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
1142 additions
and
0 deletions
+1142
-0
Documentation/devicetree/bindings/sound/pcm186x.txt
Documentation/devicetree/bindings/sound/pcm186x.txt
+42
-0
sound/soc/codecs/Kconfig
sound/soc/codecs/Kconfig
+17
-0
sound/soc/codecs/Makefile
sound/soc/codecs/Makefile
+6
-0
sound/soc/codecs/pcm186x-i2c.c
sound/soc/codecs/pcm186x-i2c.c
+69
-0
sound/soc/codecs/pcm186x-spi.c
sound/soc/codecs/pcm186x-spi.c
+69
-0
sound/soc/codecs/pcm186x.c
sound/soc/codecs/pcm186x.c
+719
-0
sound/soc/codecs/pcm186x.h
sound/soc/codecs/pcm186x.h
+220
-0
No files found.
Documentation/devicetree/bindings/sound/pcm186x.txt
0 → 100644
View file @
0583060f
Texas Instruments PCM186x Universal Audio ADC
These devices support both I2C and SPI (configured with pin strapping
on the board).
Required properties:
- compatible : "ti,pcm1862",
"ti,pcm1863",
"ti,pcm1864",
"ti,pcm1865"
- reg : The I2C address of the device for I2C, the chip select
number for SPI.
- avdd-supply: Analog core power supply (3.3v)
- dvdd-supply: Digital core power supply
- iovdd-supply: Digital IO power supply
See regulator/regulator.txt for more information
CODEC input pins:
* VINL1
* VINR1
* VINL2
* VINR2
* VINL3
* VINR3
* VINL4
* VINR4
The pins can be used in referring sound node's audio-routing property.
Example:
pcm186x: audio-codec@4a {
compatible = "ti,pcm1865";
reg = <0x4a>;
avdd-supply = <®_3v3_analog>;
dvdd-supply = <®_3v3>;
iovdd-supply = <®_1v8>;
};
sound/soc/codecs/Kconfig
View file @
0583060f
...
...
@@ -109,6 +109,8 @@ config SND_SOC_ALL_CODECS
select SND_SOC_PCM1681 if I2C
select SND_SOC_PCM179X_I2C if I2C
select SND_SOC_PCM179X_SPI if SPI_MASTER
select SND_SOC_PCM186X_I2C if I2C
select SND_SOC_PCM186X_SPI if SPI_MASTER
select SND_SOC_PCM3008
select SND_SOC_PCM3168A_I2C if I2C
select SND_SOC_PCM3168A_SPI if SPI_MASTER
...
...
@@ -660,6 +662,21 @@ config SND_SOC_PCM179X_SPI
Enable support for Texas Instruments PCM179x CODEC.
Select this if your PCM179x is connected via an SPI bus.
config SND_SOC_PCM186X
tristate
config SND_SOC_PCM186X_I2C
tristate "Texas Instruments PCM186x CODECs - I2C"
depends on I2C
select SND_SOC_PCM186X
select REGMAP_I2C
config SND_SOC_PCM186X_SPI
tristate "Texas Instruments PCM186x CODECs - SPI"
depends on SPI_MASTER
select SND_SOC_PCM186X
select REGMAP_SPI
config SND_SOC_PCM3008
tristate
...
...
sound/soc/codecs/Makefile
View file @
0583060f
...
...
@@ -105,6 +105,9 @@ snd-soc-pcm1681-objs := pcm1681.o
snd-soc-pcm179x-codec-objs
:=
pcm179x.o
snd-soc-pcm179x-i2c-objs
:=
pcm179x-i2c.o
snd-soc-pcm179x-spi-objs
:=
pcm179x-spi.o
snd-soc-pcm186x-objs
:=
pcm186x.o
snd-soc-pcm186x-i2c-objs
:=
pcm186x-i2c.o
snd-soc-pcm186x-spi-objs
:=
pcm186x-spi.o
snd-soc-pcm3008-objs
:=
pcm3008.o
snd-soc-pcm3168a-objs
:=
pcm3168a.o
snd-soc-pcm3168a-i2c-objs
:=
pcm3168a-i2c.o
...
...
@@ -344,6 +347,9 @@ obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o
obj-$(CONFIG_SND_SOC_PCM179X)
+=
snd-soc-pcm179x-codec.o
obj-$(CONFIG_SND_SOC_PCM179X_I2C)
+=
snd-soc-pcm179x-i2c.o
obj-$(CONFIG_SND_SOC_PCM179X_SPI)
+=
snd-soc-pcm179x-spi.o
obj-$(CONFIG_SND_SOC_PCM186X)
+=
snd-soc-pcm186x.o
obj-$(CONFIG_SND_SOC_PCM186X_I2C)
+=
snd-soc-pcm186x-i2c.o
obj-$(CONFIG_SND_SOC_PCM186X_SPI)
+=
snd-soc-pcm186x-spi.o
obj-$(CONFIG_SND_SOC_PCM3008)
+=
snd-soc-pcm3008.o
obj-$(CONFIG_SND_SOC_PCM3168A)
+=
snd-soc-pcm3168a.o
obj-$(CONFIG_SND_SOC_PCM3168A_I2C)
+=
snd-soc-pcm3168a-i2c.o
...
...
sound/soc/codecs/pcm186x-i2c.c
0 → 100644
View file @
0583060f
// SPDX-License-Identifier: GPL-2.0
/*
* Texas Instruments PCM186x Universal Audio ADC - I2C
*
* Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com
* Andreas Dannenberg <dannenberg@ti.com>
* Andrew F. Davis <afd@ti.com>
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include "pcm186x.h"
static
const
struct
of_device_id
pcm186x_of_match
[]
=
{
{
.
compatible
=
"ti,pcm1862"
,
.
data
=
(
void
*
)
PCM1862
},
{
.
compatible
=
"ti,pcm1863"
,
.
data
=
(
void
*
)
PCM1863
},
{
.
compatible
=
"ti,pcm1864"
,
.
data
=
(
void
*
)
PCM1864
},
{
.
compatible
=
"ti,pcm1865"
,
.
data
=
(
void
*
)
PCM1865
},
{
}
};
MODULE_DEVICE_TABLE
(
of
,
pcm186x_of_match
);
static
int
pcm186x_i2c_probe
(
struct
i2c_client
*
i2c
,
const
struct
i2c_device_id
*
id
)
{
const
enum
pcm186x_type
type
=
(
enum
pcm186x_type
)
id
->
driver_data
;
int
irq
=
i2c
->
irq
;
struct
regmap
*
regmap
;
regmap
=
devm_regmap_init_i2c
(
i2c
,
&
pcm186x_regmap
);
if
(
IS_ERR
(
regmap
))
return
PTR_ERR
(
regmap
);
return
pcm186x_probe
(
&
i2c
->
dev
,
type
,
irq
,
regmap
);
}
static
int
pcm186x_i2c_remove
(
struct
i2c_client
*
i2c
)
{
pcm186x_remove
(
&
i2c
->
dev
);
return
0
;
}
static
const
struct
i2c_device_id
pcm186x_i2c_id
[]
=
{
{
"pcm1862"
,
PCM1862
},
{
"pcm1863"
,
PCM1863
},
{
"pcm1864"
,
PCM1864
},
{
"pcm1865"
,
PCM1865
},
{
}
};
MODULE_DEVICE_TABLE
(
i2c
,
pcm186x_i2c_id
);
static
struct
i2c_driver
pcm186x_i2c_driver
=
{
.
probe
=
pcm186x_i2c_probe
,
.
remove
=
pcm186x_i2c_remove
,
.
id_table
=
pcm186x_i2c_id
,
.
driver
=
{
.
name
=
"pcm186x"
,
.
of_match_table
=
pcm186x_of_match
,
},
};
module_i2c_driver
(
pcm186x_i2c_driver
);
MODULE_AUTHOR
(
"Andreas Dannenberg <dannenberg@ti.com>"
);
MODULE_AUTHOR
(
"Andrew F. Davis <afd@ti.com>"
);
MODULE_DESCRIPTION
(
"PCM186x Universal Audio ADC I2C Interface Driver"
);
MODULE_LICENSE
(
"GPL v2"
);
sound/soc/codecs/pcm186x-spi.c
0 → 100644
View file @
0583060f
// SPDX-License-Identifier: GPL-2.0
/*
* Texas Instruments PCM186x Universal Audio ADC - SPI
*
* Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com
* Andreas Dannenberg <dannenberg@ti.com>
* Andrew F. Davis <afd@ti.com>
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include "pcm186x.h"
static
const
struct
of_device_id
pcm186x_of_match
[]
=
{
{
.
compatible
=
"ti,pcm1862"
,
.
data
=
(
void
*
)
PCM1862
},
{
.
compatible
=
"ti,pcm1863"
,
.
data
=
(
void
*
)
PCM1863
},
{
.
compatible
=
"ti,pcm1864"
,
.
data
=
(
void
*
)
PCM1864
},
{
.
compatible
=
"ti,pcm1865"
,
.
data
=
(
void
*
)
PCM1865
},
{
}
};
MODULE_DEVICE_TABLE
(
of
,
pcm186x_of_match
);
static
int
pcm186x_spi_probe
(
struct
spi_device
*
spi
)
{
const
enum
pcm186x_type
type
=
(
enum
pcm186x_type
)
spi_get_device_id
(
spi
)
->
driver_data
;
int
irq
=
spi
->
irq
;
struct
regmap
*
regmap
;
regmap
=
devm_regmap_init_spi
(
spi
,
&
pcm186x_regmap
);
if
(
IS_ERR
(
regmap
))
return
PTR_ERR
(
regmap
);
return
pcm186x_probe
(
&
spi
->
dev
,
type
,
irq
,
regmap
);
}
static
int
pcm186x_spi_remove
(
struct
spi_device
*
spi
)
{
pcm186x_remove
(
&
spi
->
dev
);
return
0
;
}
static
const
struct
spi_device_id
pcm186x_spi_id
[]
=
{
{
"pcm1862"
,
PCM1862
},
{
"pcm1863"
,
PCM1863
},
{
"pcm1864"
,
PCM1864
},
{
"pcm1865"
,
PCM1865
},
{
}
};
MODULE_DEVICE_TABLE
(
spi
,
pcm186x_spi_id
);
static
struct
spi_driver
pcm186x_spi_driver
=
{
.
probe
=
pcm186x_spi_probe
,
.
remove
=
pcm186x_spi_remove
,
.
id_table
=
pcm186x_spi_id
,
.
driver
=
{
.
name
=
"pcm186x"
,
.
of_match_table
=
pcm186x_of_match
,
},
};
module_spi_driver
(
pcm186x_spi_driver
);
MODULE_AUTHOR
(
"Andreas Dannenberg <dannenberg@ti.com>"
);
MODULE_AUTHOR
(
"Andrew F. Davis <afd@ti.com>"
);
MODULE_DESCRIPTION
(
"PCM186x Universal Audio ADC SPI Interface Driver"
);
MODULE_LICENSE
(
"GPL v2"
);
sound/soc/codecs/pcm186x.c
0 → 100644
View file @
0583060f
// SPDX-License-Identifier: GPL-2.0
/*
* Texas Instruments PCM186x Universal Audio ADC
*
* Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com
* Andreas Dannenberg <dannenberg@ti.com>
* Andrew F. Davis <afd@ti.com>
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/jack.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include "pcm186x.h"
static
const
char
*
const
pcm186x_supply_names
[]
=
{
"avdd"
,
/* Analog power supply. Connect to 3.3-V supply. */
"dvdd"
,
/* Digital power supply. Connect to 3.3-V supply. */
"iovdd"
,
/* I/O power supply. Connect to 3.3-V or 1.8-V. */
};
#define PCM186x_NUM_SUPPLIES ARRAY_SIZE(pcm186x_supply_names)
struct
pcm186x_priv
{
struct
regmap
*
regmap
;
struct
regulator_bulk_data
supplies
[
PCM186x_NUM_SUPPLIES
];
unsigned
int
sysclk
;
unsigned
int
tdm_offset
;
bool
is_tdm_mode
;
bool
is_master_mode
;
};
static
const
DECLARE_TLV_DB_SCALE
(
pcm186x_pga_tlv
,
-
1200
,
4000
,
50
);
static
const
struct
snd_kcontrol_new
pcm1863_snd_controls
[]
=
{
SOC_DOUBLE_R_S_TLV
(
"ADC Capture Volume"
,
PCM186X_PGA_VAL_CH1_L
,
PCM186X_PGA_VAL_CH1_R
,
0
,
-
24
,
80
,
7
,
0
,
pcm186x_pga_tlv
),
};
static
const
struct
snd_kcontrol_new
pcm1865_snd_controls
[]
=
{
SOC_DOUBLE_R_S_TLV
(
"ADC1 Capture Volume"
,
PCM186X_PGA_VAL_CH1_L
,
PCM186X_PGA_VAL_CH1_R
,
0
,
-
24
,
80
,
7
,
0
,
pcm186x_pga_tlv
),
SOC_DOUBLE_R_S_TLV
(
"ADC2 Capture Volume"
,
PCM186X_PGA_VAL_CH2_L
,
PCM186X_PGA_VAL_CH2_R
,
0
,
-
24
,
80
,
7
,
0
,
pcm186x_pga_tlv
),
};
static
const
unsigned
int
pcm186x_adc_input_channel_sel_value
[]
=
{
0x00
,
0x01
,
0x02
,
0x03
,
0x04
,
0x05
,
0x06
,
0x07
,
0x08
,
0x09
,
0x0a
,
0x0b
,
0x0c
,
0x0d
,
0x0e
,
0x0f
,
0x10
,
0x20
,
0x30
};
static
const
char
*
const
pcm186x_adcl_input_channel_sel_text
[]
=
{
"No Select"
,
"VINL1[SE]"
,
/* Default for ADC1L */
"VINL2[SE]"
,
/* Default for ADC2L */
"VINL2[SE] + VINL1[SE]"
,
"VINL3[SE]"
,
"VINL3[SE] + VINL1[SE]"
,
"VINL3[SE] + VINL2[SE]"
,
"VINL3[SE] + VINL2[SE] + VINL1[SE]"
,
"VINL4[SE]"
,
"VINL4[SE] + VINL1[SE]"
,
"VINL4[SE] + VINL2[SE]"
,
"VINL4[SE] + VINL2[SE] + VINL1[SE]"
,
"VINL4[SE] + VINL3[SE]"
,
"VINL4[SE] + VINL3[SE] + VINL1[SE]"
,
"VINL4[SE] + VINL3[SE] + VINL2[SE]"
,
"VINL4[SE] + VINL3[SE] + VINL2[SE] + VINL1[SE]"
,
"{VIN1P, VIN1M}[DIFF]"
,
"{VIN4P, VIN4M}[DIFF]"
,
"{VIN1P, VIN1M}[DIFF] + {VIN4P, VIN4M}[DIFF]"
};
static
const
char
*
const
pcm186x_adcr_input_channel_sel_text
[]
=
{
"No Select"
,
"VINR1[SE]"
,
/* Default for ADC1R */
"VINR2[SE]"
,
/* Default for ADC2R */
"VINR2[SE] + VINR1[SE]"
,
"VINR3[SE]"
,
"VINR3[SE] + VINR1[SE]"
,
"VINR3[SE] + VINR2[SE]"
,
"VINR3[SE] + VINR2[SE] + VINR1[SE]"
,
"VINR4[SE]"
,
"VINR4[SE] + VINR1[SE]"
,
"VINR4[SE] + VINR2[SE]"
,
"VINR4[SE] + VINR2[SE] + VINR1[SE]"
,
"VINR4[SE] + VINR3[SE]"
,
"VINR4[SE] + VINR3[SE] + VINR1[SE]"
,
"VINR4[SE] + VINR3[SE] + VINR2[SE]"
,
"VINR4[SE] + VINR3[SE] + VINR2[SE] + VINR1[SE]"
,
"{VIN2P, VIN2M}[DIFF]"
,
"{VIN3P, VIN3M}[DIFF]"
,
"{VIN2P, VIN2M}[DIFF] + {VIN3P, VIN3M}[DIFF]"
};
static
const
struct
soc_enum
pcm186x_adc_input_channel_sel
[]
=
{
SOC_VALUE_ENUM_SINGLE
(
PCM186X_ADC1_INPUT_SEL_L
,
0
,
PCM186X_ADC_INPUT_SEL_MASK
,
ARRAY_SIZE
(
pcm186x_adcl_input_channel_sel_text
),
pcm186x_adcl_input_channel_sel_text
,
pcm186x_adc_input_channel_sel_value
),
SOC_VALUE_ENUM_SINGLE
(
PCM186X_ADC1_INPUT_SEL_R
,
0
,
PCM186X_ADC_INPUT_SEL_MASK
,
ARRAY_SIZE
(
pcm186x_adcr_input_channel_sel_text
),
pcm186x_adcr_input_channel_sel_text
,
pcm186x_adc_input_channel_sel_value
),
SOC_VALUE_ENUM_SINGLE
(
PCM186X_ADC2_INPUT_SEL_L
,
0
,
PCM186X_ADC_INPUT_SEL_MASK
,
ARRAY_SIZE
(
pcm186x_adcl_input_channel_sel_text
),
pcm186x_adcl_input_channel_sel_text
,
pcm186x_adc_input_channel_sel_value
),
SOC_VALUE_ENUM_SINGLE
(
PCM186X_ADC2_INPUT_SEL_R
,
0
,
PCM186X_ADC_INPUT_SEL_MASK
,
ARRAY_SIZE
(
pcm186x_adcr_input_channel_sel_text
),
pcm186x_adcr_input_channel_sel_text
,
pcm186x_adc_input_channel_sel_value
),
};
static
const
struct
snd_kcontrol_new
pcm186x_adc_mux_controls
[]
=
{
SOC_DAPM_ENUM
(
"ADC1 Left Input"
,
pcm186x_adc_input_channel_sel
[
0
]),
SOC_DAPM_ENUM
(
"ADC1 Right Input"
,
pcm186x_adc_input_channel_sel
[
1
]),
SOC_DAPM_ENUM
(
"ADC2 Left Input"
,
pcm186x_adc_input_channel_sel
[
2
]),
SOC_DAPM_ENUM
(
"ADC2 Right Input"
,
pcm186x_adc_input_channel_sel
[
3
]),
};
static
const
struct
snd_soc_dapm_widget
pcm1863_dapm_widgets
[]
=
{
SND_SOC_DAPM_INPUT
(
"VINL1"
),
SND_SOC_DAPM_INPUT
(
"VINR1"
),
SND_SOC_DAPM_INPUT
(
"VINL2"
),
SND_SOC_DAPM_INPUT
(
"VINR2"
),
SND_SOC_DAPM_INPUT
(
"VINL3"
),
SND_SOC_DAPM_INPUT
(
"VINR3"
),
SND_SOC_DAPM_INPUT
(
"VINL4"
),
SND_SOC_DAPM_INPUT
(
"VINR4"
),
SND_SOC_DAPM_MUX
(
"ADC Left Capture Source"
,
SND_SOC_NOPM
,
0
,
0
,
&
pcm186x_adc_mux_controls
[
0
]),
SND_SOC_DAPM_MUX
(
"ADC Right Capture Source"
,
SND_SOC_NOPM
,
0
,
0
,
&
pcm186x_adc_mux_controls
[
1
]),
/*
* Put the codec into SLEEP mode when not in use, allowing the
* Energysense mechanism to operate.
*/
SND_SOC_DAPM_ADC
(
"ADC"
,
"HiFi Capture"
,
PCM186X_POWER_CTRL
,
1
,
0
),
};
static
const
struct
snd_soc_dapm_widget
pcm1865_dapm_widgets
[]
=
{
SND_SOC_DAPM_INPUT
(
"VINL1"
),
SND_SOC_DAPM_INPUT
(
"VINR1"
),
SND_SOC_DAPM_INPUT
(
"VINL2"
),
SND_SOC_DAPM_INPUT
(
"VINR2"
),
SND_SOC_DAPM_INPUT
(
"VINL3"
),
SND_SOC_DAPM_INPUT
(
"VINR3"
),
SND_SOC_DAPM_INPUT
(
"VINL4"
),
SND_SOC_DAPM_INPUT
(
"VINR4"
),
SND_SOC_DAPM_MUX
(
"ADC1 Left Capture Source"
,
SND_SOC_NOPM
,
0
,
0
,
&
pcm186x_adc_mux_controls
[
0
]),
SND_SOC_DAPM_MUX
(
"ADC1 Right Capture Source"
,
SND_SOC_NOPM
,
0
,
0
,
&
pcm186x_adc_mux_controls
[
1
]),
SND_SOC_DAPM_MUX
(
"ADC2 Left Capture Source"
,
SND_SOC_NOPM
,
0
,
0
,
&
pcm186x_adc_mux_controls
[
2
]),
SND_SOC_DAPM_MUX
(
"ADC2 Right Capture Source"
,
SND_SOC_NOPM
,
0
,
0
,
&
pcm186x_adc_mux_controls
[
3
]),
/*
* Put the codec into SLEEP mode when not in use, allowing the
* Energysense mechanism to operate.
*/
SND_SOC_DAPM_ADC
(
"ADC1"
,
"HiFi Capture 1"
,
PCM186X_POWER_CTRL
,
1
,
0
),
SND_SOC_DAPM_ADC
(
"ADC2"
,
"HiFi Capture 2"
,
PCM186X_POWER_CTRL
,
1
,
0
),
};
static
const
struct
snd_soc_dapm_route
pcm1863_dapm_routes
[]
=
{
{
"ADC Left Capture Source"
,
NULL
,
"VINL1"
},
{
"ADC Left Capture Source"
,
NULL
,
"VINR1"
},
{
"ADC Left Capture Source"
,
NULL
,
"VINL2"
},
{
"ADC Left Capture Source"
,
NULL
,
"VINR2"
},
{
"ADC Left Capture Source"
,
NULL
,
"VINL3"
},
{
"ADC Left Capture Source"
,
NULL
,
"VINR3"
},
{
"ADC Left Capture Source"
,
NULL
,
"VINL4"
},
{
"ADC Left Capture Source"
,
NULL
,
"VINR4"
},
{
"ADC"
,
NULL
,
"ADC Left Capture Source"
},
{
"ADC Right Capture Source"
,
NULL
,
"VINL1"
},
{
"ADC Right Capture Source"
,
NULL
,
"VINR1"
},
{
"ADC Right Capture Source"
,
NULL
,
"VINL2"
},
{
"ADC Right Capture Source"
,
NULL
,
"VINR2"
},
{
"ADC Right Capture Source"
,
NULL
,
"VINL3"
},
{
"ADC Right Capture Source"
,
NULL
,
"VINR3"
},
{
"ADC Right Capture Source"
,
NULL
,
"VINL4"
},
{
"ADC Right Capture Source"
,
NULL
,
"VINR4"
},
{
"ADC"
,
NULL
,
"ADC Right Capture Source"
},
};
static
const
struct
snd_soc_dapm_route
pcm1865_dapm_routes
[]
=
{
{
"ADC1 Left Capture Source"
,
NULL
,
"VINL1"
},
{
"ADC1 Left Capture Source"
,
NULL
,
"VINR1"
},
{
"ADC1 Left Capture Source"
,
NULL
,
"VINL2"
},
{
"ADC1 Left Capture Source"
,
NULL
,
"VINR2"
},
{
"ADC1 Left Capture Source"
,
NULL
,
"VINL3"
},
{
"ADC1 Left Capture Source"
,
NULL
,
"VINR3"
},
{
"ADC1 Left Capture Source"
,
NULL
,
"VINL4"
},
{
"ADC1 Left Capture Source"
,
NULL
,
"VINR4"
},
{
"ADC1"
,
NULL
,
"ADC1 Left Capture Source"
},
{
"ADC1 Right Capture Source"
,
NULL
,
"VINL1"
},
{
"ADC1 Right Capture Source"
,
NULL
,
"VINR1"
},
{
"ADC1 Right Capture Source"
,
NULL
,
"VINL2"
},
{
"ADC1 Right Capture Source"
,
NULL
,
"VINR2"
},
{
"ADC1 Right Capture Source"
,
NULL
,
"VINL3"
},
{
"ADC1 Right Capture Source"
,
NULL
,
"VINR3"
},
{
"ADC1 Right Capture Source"
,
NULL
,
"VINL4"
},
{
"ADC1 Right Capture Source"
,
NULL
,
"VINR4"
},
{
"ADC1"
,
NULL
,
"ADC1 Right Capture Source"
},
{
"ADC2 Left Capture Source"
,
NULL
,
"VINL1"
},
{
"ADC2 Left Capture Source"
,
NULL
,
"VINR1"
},
{
"ADC2 Left Capture Source"
,
NULL
,
"VINL2"
},
{
"ADC2 Left Capture Source"
,
NULL
,
"VINR2"
},
{
"ADC2 Left Capture Source"
,
NULL
,
"VINL3"
},
{
"ADC2 Left Capture Source"
,
NULL
,
"VINR3"
},
{
"ADC2 Left Capture Source"
,
NULL
,
"VINL4"
},
{
"ADC2 Left Capture Source"
,
NULL
,
"VINR4"
},
{
"ADC2"
,
NULL
,
"ADC2 Left Capture Source"
},
{
"ADC2 Right Capture Source"
,
NULL
,
"VINL1"
},
{
"ADC2 Right Capture Source"
,
NULL
,
"VINR1"
},
{
"ADC2 Right Capture Source"
,
NULL
,
"VINL2"
},
{
"ADC2 Right Capture Source"
,
NULL
,
"VINR2"
},
{
"ADC2 Right Capture Source"
,
NULL
,
"VINL3"
},
{
"ADC2 Right Capture Source"
,
NULL
,
"VINR3"
},
{
"ADC2 Right Capture Source"
,
NULL
,
"VINL4"
},
{
"ADC2 Right Capture Source"
,
NULL
,
"VINR4"
},
{
"ADC2"
,
NULL
,
"ADC2 Right Capture Source"
},
};
static
int
pcm186x_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
;
struct
pcm186x_priv
*
priv
=
snd_soc_codec_get_drvdata
(
codec
);
unsigned
int
rate
=
params_rate
(
params
);
unsigned
int
format
=
params_format
(
params
);
unsigned
int
width
=
params_width
(
params
);
unsigned
int
channels
=
params_channels
(
params
);
unsigned
int
div_lrck
;
unsigned
int
div_bck
;
u8
tdm_tx_sel
=
0
;
u8
pcm_cfg
=
0
;
dev_dbg
(
codec
->
dev
,
"%s() rate=%u format=0x%x width=%u channels=%u
\n
"
,
__func__
,
rate
,
format
,
width
,
channels
);
switch
(
width
)
{
case
16
:
pcm_cfg
=
PCM186X_PCM_CFG_RX_WLEN_16
<<
PCM186X_PCM_CFG_RX_WLEN_SHIFT
|
PCM186X_PCM_CFG_TX_WLEN_16
<<
PCM186X_PCM_CFG_TX_WLEN_SHIFT
;
break
;
case
20
:
pcm_cfg
=
PCM186X_PCM_CFG_RX_WLEN_20
<<
PCM186X_PCM_CFG_RX_WLEN_SHIFT
|
PCM186X_PCM_CFG_TX_WLEN_20
<<
PCM186X_PCM_CFG_TX_WLEN_SHIFT
;
break
;
case
24
:
pcm_cfg
=
PCM186X_PCM_CFG_RX_WLEN_24
<<
PCM186X_PCM_CFG_RX_WLEN_SHIFT
|
PCM186X_PCM_CFG_TX_WLEN_24
<<
PCM186X_PCM_CFG_TX_WLEN_SHIFT
;
break
;
case
32
:
pcm_cfg
=
PCM186X_PCM_CFG_RX_WLEN_32
<<
PCM186X_PCM_CFG_RX_WLEN_SHIFT
|
PCM186X_PCM_CFG_TX_WLEN_32
<<
PCM186X_PCM_CFG_TX_WLEN_SHIFT
;
break
;
default:
return
-
EINVAL
;
}
snd_soc_update_bits
(
codec
,
PCM186X_PCM_CFG
,
PCM186X_PCM_CFG_RX_WLEN_MASK
|
PCM186X_PCM_CFG_TX_WLEN_MASK
,
pcm_cfg
);
div_lrck
=
width
*
channels
;
if
(
priv
->
is_tdm_mode
)
{
/* Select TDM transmission data */
switch
(
channels
)
{
case
2
:
tdm_tx_sel
=
PCM186X_TDM_TX_SEL_2CH
;
break
;
case
4
:
tdm_tx_sel
=
PCM186X_TDM_TX_SEL_4CH
;
break
;
case
6
:
tdm_tx_sel
=
PCM186X_TDM_TX_SEL_6CH
;
break
;
default:
return
-
EINVAL
;
}
snd_soc_update_bits
(
codec
,
PCM186X_TDM_TX_SEL
,
PCM186X_TDM_TX_SEL_MASK
,
tdm_tx_sel
);
/* In DSP/TDM mode, the LRCLK divider must be 256 */
div_lrck
=
256
;
/* Configure 1/256 duty cycle for LRCK */
snd_soc_update_bits
(
codec
,
PCM186X_PCM_CFG
,
PCM186X_PCM_CFG_TDM_LRCK_MODE
,
PCM186X_PCM_CFG_TDM_LRCK_MODE
);
}
/* Only configure clock dividers in master mode. */
if
(
priv
->
is_master_mode
)
{
div_bck
=
priv
->
sysclk
/
(
div_lrck
*
rate
);
dev_dbg
(
codec
->
dev
,
"%s() master_clk=%u div_bck=%u div_lrck=%u
\n
"
,
__func__
,
priv
->
sysclk
,
div_bck
,
div_lrck
);
snd_soc_write
(
codec
,
PCM186X_BCK_DIV
,
div_bck
-
1
);
snd_soc_write
(
codec
,
PCM186X_LRK_DIV
,
div_lrck
-
1
);
}
return
0
;
}
static
int
pcm186x_set_fmt
(
struct
snd_soc_dai
*
dai
,
unsigned
int
format
)
{
struct
snd_soc_codec
*
codec
=
dai
->
codec
;
struct
pcm186x_priv
*
priv
=
snd_soc_codec_get_drvdata
(
codec
);
u8
clk_ctrl
=
0
;
u8
pcm_cfg
=
0
;
dev_dbg
(
codec
->
dev
,
"%s() format=0x%x
\n
"
,
__func__
,
format
);
/* set master/slave audio interface */
switch
(
format
&
SND_SOC_DAIFMT_MASTER_MASK
)
{
case
SND_SOC_DAIFMT_CBM_CFM
:
if
(
!
priv
->
sysclk
)
{
dev_err
(
codec
->
dev
,
"operating in master mode requires sysclock to be configured
\n
"
);
return
-
EINVAL
;
}
clk_ctrl
|=
PCM186X_CLK_CTRL_MST_MODE
;
priv
->
is_master_mode
=
true
;
break
;
case
SND_SOC_DAIFMT_CBS_CFS
:
priv
->
is_master_mode
=
false
;
break
;
default:
dev_err
(
codec
->
dev
,
"Invalid DAI master/slave interface
\n
"
);
return
-
EINVAL
;
}
/* set interface polarity */
switch
(
format
&
SND_SOC_DAIFMT_INV_MASK
)
{
case
SND_SOC_DAIFMT_NB_NF
:
break
;
default:
dev_err
(
codec
->
dev
,
"Inverted DAI clocks not supported
\n
"
);
return
-
EINVAL
;
}
/* set interface format */
switch
(
format
&
SND_SOC_DAIFMT_FORMAT_MASK
)
{
case
SND_SOC_DAIFMT_I2S
:
pcm_cfg
=
PCM186X_PCM_CFG_FMT_I2S
;
break
;
case
SND_SOC_DAIFMT_LEFT_J
:
pcm_cfg
=
PCM186X_PCM_CFG_FMT_LEFTJ
;
break
;
case
SND_SOC_DAIFMT_DSP_A
:
priv
->
tdm_offset
+=
1
;
/* Fall through... DSP_A uses the same basic config as DSP_B
* except we need to shift the TDM output by one BCK cycle
*/
case
SND_SOC_DAIFMT_DSP_B
:
priv
->
is_tdm_mode
=
true
;
pcm_cfg
=
PCM186X_PCM_CFG_FMT_TDM
;
break
;
default:
dev_err
(
codec
->
dev
,
"Invalid DAI format
\n
"
);
return
-
EINVAL
;
}
snd_soc_update_bits
(
codec
,
PCM186X_CLK_CTRL
,
PCM186X_CLK_CTRL_MST_MODE
,
clk_ctrl
);
snd_soc_write
(
codec
,
PCM186X_TDM_TX_OFFSET
,
priv
->
tdm_offset
);
snd_soc_update_bits
(
codec
,
PCM186X_PCM_CFG
,
PCM186X_PCM_CFG_FMT_MASK
,
pcm_cfg
);
return
0
;
}
static
int
pcm186x_set_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
;
struct
pcm186x_priv
*
priv
=
snd_soc_codec_get_drvdata
(
codec
);
unsigned
int
first_slot
,
last_slot
,
tdm_offset
;
dev_dbg
(
codec
->
dev
,
"%s() tx_mask=0x%x rx_mask=0x%x slots=%d slot_width=%d
\n
"
,
__func__
,
tx_mask
,
rx_mask
,
slots
,
slot_width
);
if
(
!
tx_mask
)
{
dev_err
(
codec
->
dev
,
"tdm tx mask must not be 0
\n
"
);
return
-
EINVAL
;
}
first_slot
=
__ffs
(
tx_mask
);
last_slot
=
__fls
(
tx_mask
);
if
(
last_slot
-
first_slot
!=
hweight32
(
tx_mask
)
-
1
)
{
dev_err
(
codec
->
dev
,
"tdm tx mask must be contiguous
\n
"
);
return
-
EINVAL
;
}
tdm_offset
=
first_slot
*
slot_width
;
if
(
tdm_offset
>
255
)
{
dev_err
(
codec
->
dev
,
"tdm tx slot selection out of bounds
\n
"
);
return
-
EINVAL
;
}
priv
->
tdm_offset
=
tdm_offset
;
return
0
;
}
static
int
pcm186x_set_dai_sysclk
(
struct
snd_soc_dai
*
dai
,
int
clk_id
,
unsigned
int
freq
,
int
dir
)
{
struct
snd_soc_codec
*
codec
=
dai
->
codec
;
struct
pcm186x_priv
*
priv
=
snd_soc_codec_get_drvdata
(
codec
);
dev_dbg
(
codec
->
dev
,
"%s() clk_id=%d freq=%u dir=%d
\n
"
,
__func__
,
clk_id
,
freq
,
dir
);
priv
->
sysclk
=
freq
;
return
0
;
}
static
const
struct
snd_soc_dai_ops
pcm186x_dai_ops
=
{
.
set_sysclk
=
pcm186x_set_dai_sysclk
,
.
set_tdm_slot
=
pcm186x_set_tdm_slot
,
.
set_fmt
=
pcm186x_set_fmt
,
.
hw_params
=
pcm186x_hw_params
,
};
static
struct
snd_soc_dai_driver
pcm1863_dai
=
{
.
name
=
"pcm1863-aif"
,
.
capture
=
{
.
stream_name
=
"Capture"
,
.
channels_min
=
1
,
.
channels_max
=
2
,
.
rates
=
PCM186X_RATES
,
.
formats
=
PCM186X_FORMATS
,
},
.
ops
=
&
pcm186x_dai_ops
,
};
static
struct
snd_soc_dai_driver
pcm1865_dai
=
{
.
name
=
"pcm1865-aif"
,
.
capture
=
{
.
stream_name
=
"Capture"
,
.
channels_min
=
1
,
.
channels_max
=
4
,
.
rates
=
PCM186X_RATES
,
.
formats
=
PCM186X_FORMATS
,
},
.
ops
=
&
pcm186x_dai_ops
,
};
static
int
pcm186x_power_on
(
struct
snd_soc_codec
*
codec
)
{
struct
pcm186x_priv
*
priv
=
snd_soc_codec_get_drvdata
(
codec
);
int
ret
=
0
;
ret
=
regulator_bulk_enable
(
ARRAY_SIZE
(
priv
->
supplies
),
priv
->
supplies
);
if
(
ret
)
return
ret
;
regcache_cache_only
(
priv
->
regmap
,
false
);
ret
=
regcache_sync
(
priv
->
regmap
);
if
(
ret
)
{
dev_err
(
codec
->
dev
,
"Failed to restore cache
\n
"
);
regcache_cache_only
(
priv
->
regmap
,
true
);
regulator_bulk_disable
(
ARRAY_SIZE
(
priv
->
supplies
),
priv
->
supplies
);
return
ret
;
}
snd_soc_update_bits
(
codec
,
PCM186X_POWER_CTRL
,
PCM186X_PWR_CTRL_PWRDN
,
0
);
return
0
;
}
static
int
pcm186x_power_off
(
struct
snd_soc_codec
*
codec
)
{
struct
pcm186x_priv
*
priv
=
snd_soc_codec_get_drvdata
(
codec
);
int
ret
;
snd_soc_update_bits
(
codec
,
PCM186X_POWER_CTRL
,
PCM186X_PWR_CTRL_PWRDN
,
PCM186X_PWR_CTRL_PWRDN
);
regcache_cache_only
(
priv
->
regmap
,
true
);
ret
=
regulator_bulk_disable
(
ARRAY_SIZE
(
priv
->
supplies
),
priv
->
supplies
);
if
(
ret
)
return
ret
;
return
0
;
}
static
int
pcm186x_set_bias_level
(
struct
snd_soc_codec
*
codec
,
enum
snd_soc_bias_level
level
)
{
dev_dbg
(
codec
->
dev
,
"## %s: %d -> %d
\n
"
,
__func__
,
snd_soc_codec_get_bias_level
(
codec
),
level
);
switch
(
level
)
{
case
SND_SOC_BIAS_ON
:
break
;
case
SND_SOC_BIAS_PREPARE
:
break
;
case
SND_SOC_BIAS_STANDBY
:
if
(
snd_soc_codec_get_bias_level
(
codec
)
==
SND_SOC_BIAS_OFF
)
pcm186x_power_on
(
codec
);
break
;
case
SND_SOC_BIAS_OFF
:
pcm186x_power_off
(
codec
);
break
;
}
return
0
;
}
static
struct
snd_soc_codec_driver
soc_codec_dev_pcm1863
=
{
.
set_bias_level
=
pcm186x_set_bias_level
,
.
component_driver
=
{
.
controls
=
pcm1863_snd_controls
,
.
num_controls
=
ARRAY_SIZE
(
pcm1863_snd_controls
),
.
dapm_widgets
=
pcm1863_dapm_widgets
,
.
num_dapm_widgets
=
ARRAY_SIZE
(
pcm1863_dapm_widgets
),
.
dapm_routes
=
pcm1863_dapm_routes
,
.
num_dapm_routes
=
ARRAY_SIZE
(
pcm1863_dapm_routes
),
},
};
static
struct
snd_soc_codec_driver
soc_codec_dev_pcm1865
=
{
.
set_bias_level
=
pcm186x_set_bias_level
,
.
suspend_bias_off
=
true
,
.
component_driver
=
{
.
controls
=
pcm1865_snd_controls
,
.
num_controls
=
ARRAY_SIZE
(
pcm1865_snd_controls
),
.
dapm_widgets
=
pcm1865_dapm_widgets
,
.
num_dapm_widgets
=
ARRAY_SIZE
(
pcm1865_dapm_widgets
),
.
dapm_routes
=
pcm1865_dapm_routes
,
.
num_dapm_routes
=
ARRAY_SIZE
(
pcm1865_dapm_routes
),
},
};
static
bool
pcm186x_volatile
(
struct
device
*
dev
,
unsigned
int
reg
)
{
switch
(
reg
)
{
case
PCM186X_PAGE
:
case
PCM186X_DEVICE_STATUS
:
case
PCM186X_FSAMPLE_STATUS
:
case
PCM186X_DIV_STATUS
:
case
PCM186X_CLK_STATUS
:
case
PCM186X_SUPPLY_STATUS
:
case
PCM186X_MMAP_STAT_CTRL
:
case
PCM186X_MMAP_ADDRESS
:
return
true
;
}
return
false
;
}
static
const
struct
regmap_range_cfg
pcm186x_range
=
{
.
name
=
"Pages"
,
.
range_max
=
PCM186X_MAX_REGISTER
,
.
selector_reg
=
PCM186X_PAGE
,
.
selector_mask
=
0xff
,
.
window_len
=
PCM186X_PAGE_LEN
,
};
const
struct
regmap_config
pcm186x_regmap
=
{
.
reg_bits
=
8
,
.
val_bits
=
8
,
.
volatile_reg
=
pcm186x_volatile
,
.
ranges
=
&
pcm186x_range
,
.
num_ranges
=
1
,
.
max_register
=
PCM186X_MAX_REGISTER
,
.
cache_type
=
REGCACHE_RBTREE
,
};
EXPORT_SYMBOL_GPL
(
pcm186x_regmap
);
int
pcm186x_probe
(
struct
device
*
dev
,
enum
pcm186x_type
type
,
int
irq
,
struct
regmap
*
regmap
)
{
struct
pcm186x_priv
*
priv
;
int
i
,
ret
;
priv
=
devm_kzalloc
(
dev
,
sizeof
(
struct
pcm186x_priv
),
GFP_KERNEL
);
if
(
!
priv
)
return
-
ENOMEM
;
dev_set_drvdata
(
dev
,
priv
);
priv
->
regmap
=
regmap
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
priv
->
supplies
);
i
++
)
priv
->
supplies
[
i
].
supply
=
pcm186x_supply_names
[
i
];
ret
=
devm_regulator_bulk_get
(
dev
,
ARRAY_SIZE
(
priv
->
supplies
),
priv
->
supplies
);
if
(
ret
)
{
dev_err
(
dev
,
"failed to request supplies: %d
\n
"
,
ret
);
return
ret
;
}
ret
=
regulator_bulk_enable
(
ARRAY_SIZE
(
priv
->
supplies
),
priv
->
supplies
);
if
(
ret
)
{
dev_err
(
dev
,
"failed enable supplies: %d
\n
"
,
ret
);
return
ret
;
}
/* Reset device registers for a consistent power-on like state */
ret
=
regmap_write
(
regmap
,
PCM186X_PAGE
,
PCM186X_RESET
);
if
(
ret
)
{
dev_err
(
dev
,
"failed to write device: %d
\n
"
,
ret
);
return
ret
;
}
ret
=
regulator_bulk_disable
(
ARRAY_SIZE
(
priv
->
supplies
),
priv
->
supplies
);
if
(
ret
)
{
dev_err
(
dev
,
"failed disable supplies: %d
\n
"
,
ret
);
return
ret
;
}
switch
(
type
)
{
case
PCM1865
:
case
PCM1864
:
ret
=
snd_soc_register_codec
(
dev
,
&
soc_codec_dev_pcm1865
,
&
pcm1865_dai
,
1
);
break
;
case
PCM1863
:
case
PCM1862
:
default:
ret
=
snd_soc_register_codec
(
dev
,
&
soc_codec_dev_pcm1863
,
&
pcm1863_dai
,
1
);
}
if
(
ret
)
{
dev_err
(
dev
,
"failed to register CODEC: %d
\n
"
,
ret
);
return
ret
;
}
return
0
;
}
EXPORT_SYMBOL_GPL
(
pcm186x_probe
);
int
pcm186x_remove
(
struct
device
*
dev
)
{
snd_soc_unregister_codec
(
dev
);
return
0
;
}
EXPORT_SYMBOL_GPL
(
pcm186x_remove
);
MODULE_AUTHOR
(
"Andreas Dannenberg <dannenberg@ti.com>"
);
MODULE_AUTHOR
(
"Andrew F. Davis <afd@ti.com>"
);
MODULE_DESCRIPTION
(
"PCM186x Universal Audio ADC driver"
);
MODULE_LICENSE
(
"GPL v2"
);
sound/soc/codecs/pcm186x.h
0 → 100644
View file @
0583060f
// SPDX-License-Identifier: GPL-2.0
/*
* Texas Instruments PCM186x Universal Audio ADC
*
* Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com
* Andreas Dannenberg <dannenberg@ti.com>
* Andrew F. Davis <afd@ti.com>
*/
#ifndef _PCM186X_H_
#define _PCM186X_H_
#include <linux/pm.h>
#include <linux/regmap.h>
enum
pcm186x_type
{
PCM1862
,
PCM1863
,
PCM1864
,
PCM1865
,
};
#define PCM186X_RATES SNDRV_PCM_RATE_8000_192000
#define PCM186X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
#define PCM186X_PAGE_LEN 0x0100
#define PCM186X_PAGE_BASE(n) (PCM186X_PAGE_LEN * n)
/* The page selection register address is the same on all pages */
#define PCM186X_PAGE 0
/* Register Definitions - Page 0 */
#define PCM186X_PGA_VAL_CH1_L (PCM186X_PAGE_BASE(0) + 1)
#define PCM186X_PGA_VAL_CH1_R (PCM186X_PAGE_BASE(0) + 2)
#define PCM186X_PGA_VAL_CH2_L (PCM186X_PAGE_BASE(0) + 3)
#define PCM186X_PGA_VAL_CH2_R (PCM186X_PAGE_BASE(0) + 4)
#define PCM186X_PGA_CTRL (PCM186X_PAGE_BASE(0) + 5)
#define PCM186X_ADC1_INPUT_SEL_L (PCM186X_PAGE_BASE(0) + 6)
#define PCM186X_ADC1_INPUT_SEL_R (PCM186X_PAGE_BASE(0) + 7)
#define PCM186X_ADC2_INPUT_SEL_L (PCM186X_PAGE_BASE(0) + 8)
#define PCM186X_ADC2_INPUT_SEL_R (PCM186X_PAGE_BASE(0) + 9)
#define PCM186X_AUXADC_INPUT_SEL (PCM186X_PAGE_BASE(0) + 10)
#define PCM186X_PCM_CFG (PCM186X_PAGE_BASE(0) + 11)
#define PCM186X_TDM_TX_SEL (PCM186X_PAGE_BASE(0) + 12)
#define PCM186X_TDM_TX_OFFSET (PCM186X_PAGE_BASE(0) + 13)
#define PCM186X_TDM_RX_OFFSET (PCM186X_PAGE_BASE(0) + 14)
#define PCM186X_DPGA_VAL_CH1_L (PCM186X_PAGE_BASE(0) + 15)
#define PCM186X_GPIO1_0_CTRL (PCM186X_PAGE_BASE(0) + 16)
#define PCM186X_GPIO3_2_CTRL (PCM186X_PAGE_BASE(0) + 17)
#define PCM186X_GPIO1_0_DIR_CTRL (PCM186X_PAGE_BASE(0) + 18)
#define PCM186X_GPIO3_2_DIR_CTRL (PCM186X_PAGE_BASE(0) + 19)
#define PCM186X_GPIO_IN_OUT (PCM186X_PAGE_BASE(0) + 20)
#define PCM186X_GPIO_PULL_CTRL (PCM186X_PAGE_BASE(0) + 21)
#define PCM186X_DPGA_VAL_CH1_R (PCM186X_PAGE_BASE(0) + 22)
#define PCM186X_DPGA_VAL_CH2_L (PCM186X_PAGE_BASE(0) + 23)
#define PCM186X_DPGA_VAL_CH2_R (PCM186X_PAGE_BASE(0) + 24)
#define PCM186X_DPGA_GAIN_CTRL (PCM186X_PAGE_BASE(0) + 25)
#define PCM186X_DPGA_MIC_CTRL (PCM186X_PAGE_BASE(0) + 26)
#define PCM186X_DIN_RESAMP_CTRL (PCM186X_PAGE_BASE(0) + 27)
#define PCM186X_CLK_CTRL (PCM186X_PAGE_BASE(0) + 32)
#define PCM186X_DSP1_CLK_DIV (PCM186X_PAGE_BASE(0) + 33)
#define PCM186X_DSP2_CLK_DIV (PCM186X_PAGE_BASE(0) + 34)
#define PCM186X_ADC_CLK_DIV (PCM186X_PAGE_BASE(0) + 35)
#define PCM186X_PLL_SCK_DIV (PCM186X_PAGE_BASE(0) + 37)
#define PCM186X_BCK_DIV (PCM186X_PAGE_BASE(0) + 38)
#define PCM186X_LRK_DIV (PCM186X_PAGE_BASE(0) + 39)
#define PCM186X_PLL_CTRL (PCM186X_PAGE_BASE(0) + 40)
#define PCM186X_PLL_P_DIV (PCM186X_PAGE_BASE(0) + 41)
#define PCM186X_PLL_R_DIV (PCM186X_PAGE_BASE(0) + 42)
#define PCM186X_PLL_J_DIV (PCM186X_PAGE_BASE(0) + 43)
#define PCM186X_PLL_D_DIV_LSB (PCM186X_PAGE_BASE(0) + 44)
#define PCM186X_PLL_D_DIV_MSB (PCM186X_PAGE_BASE(0) + 45)
#define PCM186X_SIGDET_MODE (PCM186X_PAGE_BASE(0) + 48)
#define PCM186X_SIGDET_MASK (PCM186X_PAGE_BASE(0) + 49)
#define PCM186X_SIGDET_STAT (PCM186X_PAGE_BASE(0) + 50)
#define PCM186X_SIGDET_LOSS_TIME (PCM186X_PAGE_BASE(0) + 52)
#define PCM186X_SIGDET_SCAN_TIME (PCM186X_PAGE_BASE(0) + 53)
#define PCM186X_SIGDET_INT_INTVL (PCM186X_PAGE_BASE(0) + 54)
#define PCM186X_SIGDET_DC_REF_CH1_L (PCM186X_PAGE_BASE(0) + 64)
#define PCM186X_SIGDET_DC_DIFF_CH1_L (PCM186X_PAGE_BASE(0) + 65)
#define PCM186X_SIGDET_DC_LEV_CH1_L (PCM186X_PAGE_BASE(0) + 66)
#define PCM186X_SIGDET_DC_REF_CH1_R (PCM186X_PAGE_BASE(0) + 67)
#define PCM186X_SIGDET_DC_DIFF_CH1_R (PCM186X_PAGE_BASE(0) + 68)
#define PCM186X_SIGDET_DC_LEV_CH1_R (PCM186X_PAGE_BASE(0) + 69)
#define PCM186X_SIGDET_DC_REF_CH2_L (PCM186X_PAGE_BASE(0) + 70)
#define PCM186X_SIGDET_DC_DIFF_CH2_L (PCM186X_PAGE_BASE(0) + 71)
#define PCM186X_SIGDET_DC_LEV_CH2_L (PCM186X_PAGE_BASE(0) + 72)
#define PCM186X_SIGDET_DC_REF_CH2_R (PCM186X_PAGE_BASE(0) + 73)
#define PCM186X_SIGDET_DC_DIFF_CH2_R (PCM186X_PAGE_BASE(0) + 74)
#define PCM186X_SIGDET_DC_LEV_CH2_R (PCM186X_PAGE_BASE(0) + 75)
#define PCM186X_SIGDET_DC_REF_CH3_L (PCM186X_PAGE_BASE(0) + 76)
#define PCM186X_SIGDET_DC_DIFF_CH3_L (PCM186X_PAGE_BASE(0) + 77)
#define PCM186X_SIGDET_DC_LEV_CH3_L (PCM186X_PAGE_BASE(0) + 78)
#define PCM186X_SIGDET_DC_REF_CH3_R (PCM186X_PAGE_BASE(0) + 79)
#define PCM186X_SIGDET_DC_DIFF_CH3_R (PCM186X_PAGE_BASE(0) + 80)
#define PCM186X_SIGDET_DC_LEV_CH3_R (PCM186X_PAGE_BASE(0) + 81)
#define PCM186X_SIGDET_DC_REF_CH4_L (PCM186X_PAGE_BASE(0) + 82)
#define PCM186X_SIGDET_DC_DIFF_CH4_L (PCM186X_PAGE_BASE(0) + 83)
#define PCM186X_SIGDET_DC_LEV_CH4_L (PCM186X_PAGE_BASE(0) + 84)
#define PCM186X_SIGDET_DC_REF_CH4_R (PCM186X_PAGE_BASE(0) + 85)
#define PCM186X_SIGDET_DC_DIFF_CH4_R (PCM186X_PAGE_BASE(0) + 86)
#define PCM186X_SIGDET_DC_LEV_CH4_R (PCM186X_PAGE_BASE(0) + 87)
#define PCM186X_AUXADC_DATA_CTRL (PCM186X_PAGE_BASE(0) + 88)
#define PCM186X_AUXADC_DATA_LSB (PCM186X_PAGE_BASE(0) + 89)
#define PCM186X_AUXADC_DATA_MSB (PCM186X_PAGE_BASE(0) + 90)
#define PCM186X_INT_ENABLE (PCM186X_PAGE_BASE(0) + 96)
#define PCM186X_INT_FLAG (PCM186X_PAGE_BASE(0) + 97)
#define PCM186X_INT_POL_WIDTH (PCM186X_PAGE_BASE(0) + 98)
#define PCM186X_POWER_CTRL (PCM186X_PAGE_BASE(0) + 112)
#define PCM186X_FILTER_MUTE_CTRL (PCM186X_PAGE_BASE(0) + 113)
#define PCM186X_DEVICE_STATUS (PCM186X_PAGE_BASE(0) + 114)
#define PCM186X_FSAMPLE_STATUS (PCM186X_PAGE_BASE(0) + 115)
#define PCM186X_DIV_STATUS (PCM186X_PAGE_BASE(0) + 116)
#define PCM186X_CLK_STATUS (PCM186X_PAGE_BASE(0) + 117)
#define PCM186X_SUPPLY_STATUS (PCM186X_PAGE_BASE(0) + 120)
/* Register Definitions - Page 1 */
#define PCM186X_MMAP_STAT_CTRL (PCM186X_PAGE_BASE(1) + 1)
#define PCM186X_MMAP_ADDRESS (PCM186X_PAGE_BASE(1) + 2)
#define PCM186X_MEM_WDATA0 (PCM186X_PAGE_BASE(1) + 4)
#define PCM186X_MEM_WDATA1 (PCM186X_PAGE_BASE(1) + 5)
#define PCM186X_MEM_WDATA2 (PCM186X_PAGE_BASE(1) + 6)
#define PCM186X_MEM_WDATA3 (PCM186X_PAGE_BASE(1) + 7)
#define PCM186X_MEM_RDATA0 (PCM186X_PAGE_BASE(1) + 8)
#define PCM186X_MEM_RDATA1 (PCM186X_PAGE_BASE(1) + 9)
#define PCM186X_MEM_RDATA2 (PCM186X_PAGE_BASE(1) + 10)
#define PCM186X_MEM_RDATA3 (PCM186X_PAGE_BASE(1) + 11)
/* Register Definitions - Page 3 */
#define PCM186X_OSC_PWR_DOWN_CTRL (PCM186X_PAGE_BASE(3) + 18)
#define PCM186X_MIC_BIAS_CTRL (PCM186X_PAGE_BASE(3) + 21)
/* Register Definitions - Page 253 */
#define PCM186X_CURR_TRIM_CTRL (PCM186X_PAGE_BASE(253) + 20)
#define PCM186X_MAX_REGISTER PCM186X_CURR_TRIM_CTRL
/* PCM186X_PAGE */
#define PCM186X_RESET 0xff
/* PCM186X_ADCX_INPUT_SEL_X */
#define PCM186X_ADC_INPUT_SEL_POL BIT(7)
#define PCM186X_ADC_INPUT_SEL_MASK GENMASK(5, 0)
/* PCM186X_PCM_CFG */
#define PCM186X_PCM_CFG_RX_WLEN_MASK GENMASK(7, 6)
#define PCM186X_PCM_CFG_RX_WLEN_SHIFT 6
#define PCM186X_PCM_CFG_RX_WLEN_32 0x00
#define PCM186X_PCM_CFG_RX_WLEN_24 0x01
#define PCM186X_PCM_CFG_RX_WLEN_20 0x02
#define PCM186X_PCM_CFG_RX_WLEN_16 0x03
#define PCM186X_PCM_CFG_TDM_LRCK_MODE BIT(4)
#define PCM186X_PCM_CFG_TX_WLEN_MASK GENMASK(3, 2)
#define PCM186X_PCM_CFG_TX_WLEN_SHIFT 2
#define PCM186X_PCM_CFG_TX_WLEN_32 0x00
#define PCM186X_PCM_CFG_TX_WLEN_24 0x01
#define PCM186X_PCM_CFG_TX_WLEN_20 0x02
#define PCM186X_PCM_CFG_TX_WLEN_16 0x03
#define PCM186X_PCM_CFG_FMT_MASK GENMASK(1, 0)
#define PCM186X_PCM_CFG_FMT_SHIFT 0
#define PCM186X_PCM_CFG_FMT_I2S 0x00
#define PCM186X_PCM_CFG_FMT_LEFTJ 0x01
#define PCM186X_PCM_CFG_FMT_RIGHTJ 0x02
#define PCM186X_PCM_CFG_FMT_TDM 0x03
/* PCM186X_TDM_TX_SEL */
#define PCM186X_TDM_TX_SEL_2CH 0x00
#define PCM186X_TDM_TX_SEL_4CH 0x01
#define PCM186X_TDM_TX_SEL_6CH 0x02
#define PCM186X_TDM_TX_SEL_MASK 0x03
/* PCM186X_CLK_CTRL */
#define PCM186X_CLK_CTRL_SCK_XI_SEL1 BIT(7)
#define PCM186X_CLK_CTRL_SCK_XI_SEL0 BIT(6)
#define PCM186X_CLK_CTRL_SCK_SRC_PLL BIT(5)
#define PCM186X_CLK_CTRL_MST_MODE BIT(4)
#define PCM186X_CLK_CTRL_ADC_SRC_PLL BIT(3)
#define PCM186X_CLK_CTRL_DSP2_SRC_PLL BIT(2)
#define PCM186X_CLK_CTRL_DSP1_SRC_PLL BIT(1)
#define PCM186X_CLK_CTRL_CLKDET_EN BIT(0)
/* PCM186X_PLL_CTRL */
#define PCM186X_PLL_CTRL_LOCK BIT(4)
#define PCM186X_PLL_CTRL_REF_SEL BIT(1)
#define PCM186X_PLL_CTRL_EN BIT(0)
/* PCM186X_POWER_CTRL */
#define PCM186X_PWR_CTRL_PWRDN BIT(2)
#define PCM186X_PWR_CTRL_SLEEP BIT(1)
#define PCM186X_PWR_CTRL_STBY BIT(0)
/* PCM186X_CLK_STATUS */
#define PCM186X_CLK_STATUS_LRCKHLT BIT(6)
#define PCM186X_CLK_STATUS_BCKHLT BIT(5)
#define PCM186X_CLK_STATUS_SCKHLT BIT(4)
#define PCM186X_CLK_STATUS_LRCKERR BIT(2)
#define PCM186X_CLK_STATUS_BCKERR BIT(1)
#define PCM186X_CLK_STATUS_SCKERR BIT(0)
/* PCM186X_SUPPLY_STATUS */
#define PCM186X_SUPPLY_STATUS_DVDD BIT(2)
#define PCM186X_SUPPLY_STATUS_AVDD BIT(1)
#define PCM186X_SUPPLY_STATUS_LDO BIT(0)
/* PCM186X_MMAP_STAT_CTRL */
#define PCM186X_MMAP_STAT_DONE BIT(4)
#define PCM186X_MMAP_STAT_BUSY BIT(2)
#define PCM186X_MMAP_STAT_R_REQ BIT(1)
#define PCM186X_MMAP_STAT_W_REQ BIT(0)
extern
const
struct
regmap_config
pcm186x_regmap
;
int
pcm186x_probe
(
struct
device
*
dev
,
enum
pcm186x_type
type
,
int
irq
,
struct
regmap
*
regmap
);
int
pcm186x_remove
(
struct
device
*
dev
);
#endif
/* _PCM186X_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