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
89c172e2
Commit
89c172e2
authored
Dec 23, 2015
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'asoc/topic/pcm3168a' into asoc-next
parents
a93202fa
a9b17a63
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
1077 additions
and
0 deletions
+1077
-0
Documentation/devicetree/bindings/sound/ti,pcm3168a.txt
Documentation/devicetree/bindings/sound/ti,pcm3168a.txt
+48
-0
include/sound/soc.h
include/sound/soc.h
+8
-0
sound/soc/codecs/Kconfig
sound/soc/codecs/Kconfig
+17
-0
sound/soc/codecs/Makefile
sound/soc/codecs/Makefile
+6
-0
sound/soc/codecs/pcm3168a-i2c.c
sound/soc/codecs/pcm3168a-i2c.c
+66
-0
sound/soc/codecs/pcm3168a-spi.c
sound/soc/codecs/pcm3168a-spi.c
+65
-0
sound/soc/codecs/pcm3168a.c
sound/soc/codecs/pcm3168a.c
+767
-0
sound/soc/codecs/pcm3168a.h
sound/soc/codecs/pcm3168a.h
+100
-0
No files found.
Documentation/devicetree/bindings/sound/ti,pcm3168a.txt
0 → 100644
View file @
89c172e2
Texas Instruments pcm3168a DT bindings
This driver supports both SPI and I2C bus access for this codec
Required properties:
- compatible: "ti,pcm3168a"
- clocks : Contains an entry for each entry in clock-names
- clock-names : Includes the following entries:
"scki" The system clock
- VDD1-supply : Digital power supply regulator 1 (+3.3V)
- VDD2-supply : Digital power supply regulator 2 (+3.3V)
- VCCAD1-supply : ADC power supply regulator 1 (+5V)
- VCCAD2-supply : ADC power supply regulator 2 (+5V)
- VCCDA1-supply : DAC power supply regulator 1 (+5V)
- VCCDA2-supply : DAC power supply regulator 2 (+5V)
For required properties on SPI/I2C, consult SPI/I2C device tree documentation
Examples:
i2c0: i2c0@0 {
...
pcm3168a: audio-codec@44 {
compatible = "ti,pcm3168a";
reg = <0x44>;
clocks = <&clk_core CLK_AUDIO>;
clock-names = "scki";
VDD1-supply = <&supply3v3>;
VDD2-supply = <&supply3v3>;
VCCAD1-supply = <&supply5v0>;
VCCAD2-supply = <&supply5v0>;
VCCDA1-supply = <&supply5v0>;
VCCDA2-supply = <&supply5v0>;
pinctrl-names = "default";
pinctrl-0 = <&dac_clk_pin>;
};
};
include/sound/soc.h
View file @
89c172e2
...
@@ -110,6 +110,14 @@
...
@@ -110,6 +110,14 @@
.put = snd_soc_put_volsw, \
.put = snd_soc_put_volsw, \
.private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \
.private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \
max, invert, 0) }
max, invert, 0) }
#define SOC_DOUBLE_STS(xname, reg, shift_left, shift_right, max, invert) \
{ \
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
.access = SNDRV_CTL_ELEM_ACCESS_READ | \
SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
.private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \
max, invert, 0) }
#define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \
#define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
.info = snd_soc_info_volsw, \
.info = snd_soc_info_volsw, \
...
...
sound/soc/codecs/Kconfig
View file @
89c172e2
...
@@ -85,6 +85,8 @@ config SND_SOC_ALL_CODECS
...
@@ -85,6 +85,8 @@ config SND_SOC_ALL_CODECS
select SND_SOC_PCM1681 if I2C
select SND_SOC_PCM1681 if I2C
select SND_SOC_PCM1792A if SPI_MASTER
select SND_SOC_PCM1792A if SPI_MASTER
select SND_SOC_PCM3008
select SND_SOC_PCM3008
select SND_SOC_PCM3168A_I2C if I2C
select SND_SOC_PCM3168A_SPI if SPI_MASTER
select SND_SOC_PCM512x_I2C if I2C
select SND_SOC_PCM512x_I2C if I2C
select SND_SOC_PCM512x_SPI if SPI_MASTER
select SND_SOC_PCM512x_SPI if SPI_MASTER
select SND_SOC_RT286 if I2C
select SND_SOC_RT286 if I2C
...
@@ -506,6 +508,21 @@ config SND_SOC_PCM1792A
...
@@ -506,6 +508,21 @@ config SND_SOC_PCM1792A
config SND_SOC_PCM3008
config SND_SOC_PCM3008
tristate
tristate
config SND_SOC_PCM3168A
tristate
config SND_SOC_PCM3168A_I2C
tristate "Texas Instruments PCM3168A CODEC - I2C"
depends on I2C
select SND_SOC_PCM3168A
select REGMAP_I2C
config SND_SOC_PCM3168A_SPI
tristate "Texas Instruments PCM3168A CODEC - SPI"
depends on SPI_MASTER
select SND_SOC_PCM3168A
select REGMAP_SPI
config SND_SOC_PCM512x
config SND_SOC_PCM512x
tristate
tristate
...
...
sound/soc/codecs/Makefile
View file @
89c172e2
...
@@ -78,6 +78,9 @@ snd-soc-nau8825-objs := nau8825.o
...
@@ -78,6 +78,9 @@ snd-soc-nau8825-objs := nau8825.o
snd-soc-pcm1681-objs
:=
pcm1681.o
snd-soc-pcm1681-objs
:=
pcm1681.o
snd-soc-pcm1792a-codec-objs
:=
pcm1792a.o
snd-soc-pcm1792a-codec-objs
:=
pcm1792a.o
snd-soc-pcm3008-objs
:=
pcm3008.o
snd-soc-pcm3008-objs
:=
pcm3008.o
snd-soc-pcm3168a-objs
:=
pcm3168a.o
snd-soc-pcm3168a-i2c-objs
:=
pcm3168a-i2c.o
snd-soc-pcm3168a-spi-objs
:=
pcm3168a-spi.o
snd-soc-pcm512x-objs
:=
pcm512x.o
snd-soc-pcm512x-objs
:=
pcm512x.o
snd-soc-pcm512x-i2c-objs
:=
pcm512x-i2c.o
snd-soc-pcm512x-i2c-objs
:=
pcm512x-i2c.o
snd-soc-pcm512x-spi-objs
:=
pcm512x-spi.o
snd-soc-pcm512x-spi-objs
:=
pcm512x-spi.o
...
@@ -273,6 +276,9 @@ obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o
...
@@ -273,6 +276,9 @@ obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o
obj-$(CONFIG_SND_SOC_PCM1681)
+=
snd-soc-pcm1681.o
obj-$(CONFIG_SND_SOC_PCM1681)
+=
snd-soc-pcm1681.o
obj-$(CONFIG_SND_SOC_PCM1792A)
+=
snd-soc-pcm1792a-codec.o
obj-$(CONFIG_SND_SOC_PCM1792A)
+=
snd-soc-pcm1792a-codec.o
obj-$(CONFIG_SND_SOC_PCM3008)
+=
snd-soc-pcm3008.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
obj-$(CONFIG_SND_SOC_PCM3168A_SPI)
+=
snd-soc-pcm3168a-spi.o
obj-$(CONFIG_SND_SOC_PCM512x)
+=
snd-soc-pcm512x.o
obj-$(CONFIG_SND_SOC_PCM512x)
+=
snd-soc-pcm512x.o
obj-$(CONFIG_SND_SOC_PCM512x_I2C)
+=
snd-soc-pcm512x-i2c.o
obj-$(CONFIG_SND_SOC_PCM512x_I2C)
+=
snd-soc-pcm512x-i2c.o
obj-$(CONFIG_SND_SOC_PCM512x_SPI)
+=
snd-soc-pcm512x-spi.o
obj-$(CONFIG_SND_SOC_PCM512x_SPI)
+=
snd-soc-pcm512x-spi.o
...
...
sound/soc/codecs/pcm3168a-i2c.c
0 → 100644
View file @
89c172e2
/*
* PCM3168A codec i2c driver
*
* Copyright (C) 2015 Imagination Technologies Ltd.
*
* Author: Damien Horsley <Damien.Horsley@imgtec.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*/
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/module.h>
#include <sound/soc.h>
#include "pcm3168a.h"
static
int
pcm3168a_i2c_probe
(
struct
i2c_client
*
i2c
,
const
struct
i2c_device_id
*
id
)
{
struct
regmap
*
regmap
;
regmap
=
devm_regmap_init_i2c
(
i2c
,
&
pcm3168a_regmap
);
if
(
IS_ERR
(
regmap
))
return
PTR_ERR
(
regmap
);
return
pcm3168a_probe
(
&
i2c
->
dev
,
regmap
);
}
static
int
pcm3168a_i2c_remove
(
struct
i2c_client
*
i2c
)
{
pcm3168a_remove
(
&
i2c
->
dev
);
return
0
;
}
static
const
struct
i2c_device_id
pcm3168a_i2c_id
[]
=
{
{
"pcm3168a"
,
},
{
}
};
MODULE_DEVICE_TABLE
(
i2c
,
pcm3168a_i2c_id
);
static
const
struct
of_device_id
pcm3168a_of_match
[]
=
{
{
.
compatible
=
"ti,pcm3168a"
,
},
{
}
};
MODULE_DEVICE_TABLE
(
of
,
pcm3168a_of_match
);
static
struct
i2c_driver
pcm3168a_i2c_driver
=
{
.
probe
=
pcm3168a_i2c_probe
,
.
remove
=
pcm3168a_i2c_remove
,
.
id_table
=
pcm3168a_i2c_id
,
.
driver
=
{
.
name
=
"pcm3168a"
,
.
of_match_table
=
pcm3168a_of_match
,
.
pm
=
&
pcm3168a_pm_ops
,
},
};
module_i2c_driver
(
pcm3168a_i2c_driver
);
MODULE_DESCRIPTION
(
"PCM3168A I2C codec driver"
);
MODULE_AUTHOR
(
"Damien Horsley <Damien.Horsley@imgtec.com>"
);
MODULE_LICENSE
(
"GPL v2"
);
sound/soc/codecs/pcm3168a-spi.c
0 → 100644
View file @
89c172e2
/*
* PCM3168A codec spi driver
*
* Copyright (C) 2015 Imagination Technologies Ltd.
*
* Author: Damien Horsley <Damien.Horsley@imgtec.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <sound/soc.h>
#include "pcm3168a.h"
static
int
pcm3168a_spi_probe
(
struct
spi_device
*
spi
)
{
struct
regmap
*
regmap
;
regmap
=
devm_regmap_init_spi
(
spi
,
&
pcm3168a_regmap
);
if
(
IS_ERR
(
regmap
))
return
PTR_ERR
(
regmap
);
return
pcm3168a_probe
(
&
spi
->
dev
,
regmap
);
}
static
int
pcm3168a_spi_remove
(
struct
spi_device
*
spi
)
{
pcm3168a_remove
(
&
spi
->
dev
);
return
0
;
}
static
const
struct
spi_device_id
pcm3168a_spi_id
[]
=
{
{
"pcm3168a"
,
},
{
},
};
MODULE_DEVICE_TABLE
(
spi
,
pcm3168a_spi_id
);
static
const
struct
of_device_id
pcm3168a_of_match
[]
=
{
{
.
compatible
=
"ti,pcm3168a"
,
},
{
}
};
MODULE_DEVICE_TABLE
(
of
,
pcm3168a_of_match
);
static
struct
spi_driver
pcm3168a_spi_driver
=
{
.
probe
=
pcm3168a_spi_probe
,
.
remove
=
pcm3168a_spi_remove
,
.
id_table
=
pcm3168a_spi_id
,
.
driver
=
{
.
name
=
"pcm3168a"
,
.
of_match_table
=
pcm3168a_of_match
,
.
pm
=
&
pcm3168a_pm_ops
,
},
};
module_spi_driver
(
pcm3168a_spi_driver
);
MODULE_DESCRIPTION
(
"PCM3168A SPI codec driver"
);
MODULE_AUTHOR
(
"Damien Horsley <Damien.Horsley@imgtec.com>"
);
MODULE_LICENSE
(
"GPL v2"
);
sound/soc/codecs/pcm3168a.c
0 → 100644
View file @
89c172e2
/*
* PCM3168A codec driver
*
* Copyright (C) 2015 Imagination Technologies Ltd.
*
* Author: Damien Horsley <Damien.Horsley@imgtec.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/tlv.h>
#include "pcm3168a.h"
#define PCM3168A_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_3LE | \
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
#define PCM3168A_FMT_I2S 0x0
#define PCM3168A_FMT_LEFT_J 0x1
#define PCM3168A_FMT_RIGHT_J 0x2
#define PCM3168A_FMT_RIGHT_J_16 0x3
#define PCM3168A_FMT_DSP_A 0x4
#define PCM3168A_FMT_DSP_B 0x5
#define PCM3168A_FMT_DSP_MASK 0x4
#define PCM3168A_NUM_SUPPLIES 6
static
const
char
*
const
pcm3168a_supply_names
[
PCM3168A_NUM_SUPPLIES
]
=
{
"VDD1"
,
"VDD2"
,
"VCCAD1"
,
"VCCAD2"
,
"VCCDA1"
,
"VCCDA2"
};
struct
pcm3168a_priv
{
struct
regulator_bulk_data
supplies
[
PCM3168A_NUM_SUPPLIES
];
struct
regmap
*
regmap
;
struct
clk
*
scki
;
bool
adc_master_mode
;
bool
dac_master_mode
;
unsigned
long
sysclk
;
unsigned
int
adc_fmt
;
unsigned
int
dac_fmt
;
};
static
const
char
*
const
pcm3168a_roll_off
[]
=
{
"Sharp"
,
"Slow"
};
static
SOC_ENUM_SINGLE_DECL
(
pcm3168a_d1_roll_off
,
PCM3168A_DAC_OP_FLT
,
PCM3168A_DAC_FLT_SHIFT
,
pcm3168a_roll_off
);
static
SOC_ENUM_SINGLE_DECL
(
pcm3168a_d2_roll_off
,
PCM3168A_DAC_OP_FLT
,
PCM3168A_DAC_FLT_SHIFT
+
1
,
pcm3168a_roll_off
);
static
SOC_ENUM_SINGLE_DECL
(
pcm3168a_d3_roll_off
,
PCM3168A_DAC_OP_FLT
,
PCM3168A_DAC_FLT_SHIFT
+
2
,
pcm3168a_roll_off
);
static
SOC_ENUM_SINGLE_DECL
(
pcm3168a_d4_roll_off
,
PCM3168A_DAC_OP_FLT
,
PCM3168A_DAC_FLT_SHIFT
+
3
,
pcm3168a_roll_off
);
static
const
char
*
const
pcm3168a_volume_type
[]
=
{
"Individual"
,
"Master + Individual"
};
static
SOC_ENUM_SINGLE_DECL
(
pcm3168a_dac_volume_type
,
PCM3168A_DAC_ATT_DEMP_ZF
,
PCM3168A_DAC_ATMDDA_SHIFT
,
pcm3168a_volume_type
);
static
const
char
*
const
pcm3168a_att_speed_mult
[]
=
{
"2048"
,
"4096"
};
static
SOC_ENUM_SINGLE_DECL
(
pcm3168a_dac_att_mult
,
PCM3168A_DAC_ATT_DEMP_ZF
,
PCM3168A_DAC_ATSPDA_SHIFT
,
pcm3168a_att_speed_mult
);
static
const
char
*
const
pcm3168a_demp
[]
=
{
"Disabled"
,
"48khz"
,
"44.1khz"
,
"32khz"
};
static
SOC_ENUM_SINGLE_DECL
(
pcm3168a_dac_demp
,
PCM3168A_DAC_ATT_DEMP_ZF
,
PCM3168A_DAC_DEMP_SHIFT
,
pcm3168a_demp
);
static
const
char
*
const
pcm3168a_zf_func
[]
=
{
"DAC 1/2/3/4 AND"
,
"DAC 1/2/3/4 OR"
,
"DAC 1/2/3 AND"
,
"DAC 1/2/3 OR"
,
"DAC 4 AND"
,
"DAC 4 OR"
};
static
SOC_ENUM_SINGLE_DECL
(
pcm3168a_dac_zf_func
,
PCM3168A_DAC_ATT_DEMP_ZF
,
PCM3168A_DAC_AZRO_SHIFT
,
pcm3168a_zf_func
);
static
const
char
*
const
pcm3168a_pol
[]
=
{
"Active High"
,
"Active Low"
};
static
SOC_ENUM_SINGLE_DECL
(
pcm3168a_dac_zf_pol
,
PCM3168A_DAC_ATT_DEMP_ZF
,
PCM3168A_DAC_ATSPDA_SHIFT
,
pcm3168a_pol
);
static
const
char
*
const
pcm3168a_con
[]
=
{
"Differential"
,
"Single-Ended"
};
static
SOC_ENUM_DOUBLE_DECL
(
pcm3168a_adc1_con
,
PCM3168A_ADC_SEAD
,
0
,
1
,
pcm3168a_con
);
static
SOC_ENUM_DOUBLE_DECL
(
pcm3168a_adc2_con
,
PCM3168A_ADC_SEAD
,
2
,
3
,
pcm3168a_con
);
static
SOC_ENUM_DOUBLE_DECL
(
pcm3168a_adc3_con
,
PCM3168A_ADC_SEAD
,
4
,
5
,
pcm3168a_con
);
static
SOC_ENUM_SINGLE_DECL
(
pcm3168a_adc_volume_type
,
PCM3168A_ADC_ATT_OVF
,
PCM3168A_ADC_ATMDAD_SHIFT
,
pcm3168a_volume_type
);
static
SOC_ENUM_SINGLE_DECL
(
pcm3168a_adc_att_mult
,
PCM3168A_ADC_ATT_OVF
,
PCM3168A_ADC_ATSPAD_SHIFT
,
pcm3168a_att_speed_mult
);
static
SOC_ENUM_SINGLE_DECL
(
pcm3168a_adc_ov_pol
,
PCM3168A_ADC_ATT_OVF
,
PCM3168A_ADC_OVFP_SHIFT
,
pcm3168a_pol
);
/* -100db to 0db, register values 0-54 cause mute */
static
const
DECLARE_TLV_DB_SCALE
(
pcm3168a_dac_tlv
,
-
10050
,
50
,
1
);
/* -100db to 20db, register values 0-14 cause mute */
static
const
DECLARE_TLV_DB_SCALE
(
pcm3168a_adc_tlv
,
-
10050
,
50
,
1
);
static
const
struct
snd_kcontrol_new
pcm3168a_snd_controls
[]
=
{
SOC_SINGLE
(
"DAC Power-Save Switch"
,
PCM3168A_DAC_PWR_MST_FMT
,
PCM3168A_DAC_PSMDA_SHIFT
,
1
,
1
),
SOC_ENUM
(
"DAC1 Digital Filter roll-off"
,
pcm3168a_d1_roll_off
),
SOC_ENUM
(
"DAC2 Digital Filter roll-off"
,
pcm3168a_d2_roll_off
),
SOC_ENUM
(
"DAC3 Digital Filter roll-off"
,
pcm3168a_d3_roll_off
),
SOC_ENUM
(
"DAC4 Digital Filter roll-off"
,
pcm3168a_d4_roll_off
),
SOC_DOUBLE
(
"DAC1 Invert Switch"
,
PCM3168A_DAC_INV
,
0
,
1
,
1
,
0
),
SOC_DOUBLE
(
"DAC2 Invert Switch"
,
PCM3168A_DAC_INV
,
2
,
3
,
1
,
0
),
SOC_DOUBLE
(
"DAC3 Invert Switch"
,
PCM3168A_DAC_INV
,
4
,
5
,
1
,
0
),
SOC_DOUBLE
(
"DAC4 Invert Switch"
,
PCM3168A_DAC_INV
,
6
,
7
,
1
,
0
),
SOC_DOUBLE_STS
(
"DAC1 Zero Flag"
,
PCM3168A_DAC_ZERO
,
0
,
1
,
1
,
0
),
SOC_DOUBLE_STS
(
"DAC2 Zero Flag"
,
PCM3168A_DAC_ZERO
,
2
,
3
,
1
,
0
),
SOC_DOUBLE_STS
(
"DAC3 Zero Flag"
,
PCM3168A_DAC_ZERO
,
4
,
5
,
1
,
0
),
SOC_DOUBLE_STS
(
"DAC4 Zero Flag"
,
PCM3168A_DAC_ZERO
,
6
,
7
,
1
,
0
),
SOC_ENUM
(
"DAC Volume Control Type"
,
pcm3168a_dac_volume_type
),
SOC_ENUM
(
"DAC Volume Rate Multiplier"
,
pcm3168a_dac_att_mult
),
SOC_ENUM
(
"DAC De-Emphasis"
,
pcm3168a_dac_demp
),
SOC_ENUM
(
"DAC Zero Flag Function"
,
pcm3168a_dac_zf_func
),
SOC_ENUM
(
"DAC Zero Flag Polarity"
,
pcm3168a_dac_zf_pol
),
SOC_SINGLE_RANGE_TLV
(
"Master Playback Volume"
,
PCM3168A_DAC_VOL_MASTER
,
0
,
54
,
255
,
0
,
pcm3168a_dac_tlv
),
SOC_DOUBLE_R_RANGE_TLV
(
"DAC1 Playback Volume"
,
PCM3168A_DAC_VOL_CHAN_START
,
PCM3168A_DAC_VOL_CHAN_START
+
1
,
0
,
54
,
255
,
0
,
pcm3168a_dac_tlv
),
SOC_DOUBLE_R_RANGE_TLV
(
"DAC2 Playback Volume"
,
PCM3168A_DAC_VOL_CHAN_START
+
2
,
PCM3168A_DAC_VOL_CHAN_START
+
3
,
0
,
54
,
255
,
0
,
pcm3168a_dac_tlv
),
SOC_DOUBLE_R_RANGE_TLV
(
"DAC3 Playback Volume"
,
PCM3168A_DAC_VOL_CHAN_START
+
4
,
PCM3168A_DAC_VOL_CHAN_START
+
5
,
0
,
54
,
255
,
0
,
pcm3168a_dac_tlv
),
SOC_DOUBLE_R_RANGE_TLV
(
"DAC4 Playback Volume"
,
PCM3168A_DAC_VOL_CHAN_START
+
6
,
PCM3168A_DAC_VOL_CHAN_START
+
7
,
0
,
54
,
255
,
0
,
pcm3168a_dac_tlv
),
SOC_SINGLE
(
"ADC1 High-Pass Filter Switch"
,
PCM3168A_ADC_PWR_HPFB
,
PCM3168A_ADC_BYP_SHIFT
,
1
,
1
),
SOC_SINGLE
(
"ADC2 High-Pass Filter Switch"
,
PCM3168A_ADC_PWR_HPFB
,
PCM3168A_ADC_BYP_SHIFT
+
1
,
1
,
1
),
SOC_SINGLE
(
"ADC3 High-Pass Filter Switch"
,
PCM3168A_ADC_PWR_HPFB
,
PCM3168A_ADC_BYP_SHIFT
+
2
,
1
,
1
),
SOC_ENUM
(
"ADC1 Connection Type"
,
pcm3168a_adc1_con
),
SOC_ENUM
(
"ADC2 Connection Type"
,
pcm3168a_adc2_con
),
SOC_ENUM
(
"ADC3 Connection Type"
,
pcm3168a_adc3_con
),
SOC_DOUBLE
(
"ADC1 Invert Switch"
,
PCM3168A_ADC_INV
,
0
,
1
,
1
,
0
),
SOC_DOUBLE
(
"ADC2 Invert Switch"
,
PCM3168A_ADC_INV
,
2
,
3
,
1
,
0
),
SOC_DOUBLE
(
"ADC3 Invert Switch"
,
PCM3168A_ADC_INV
,
4
,
5
,
1
,
0
),
SOC_DOUBLE
(
"ADC1 Mute Switch"
,
PCM3168A_ADC_MUTE
,
0
,
1
,
1
,
0
),
SOC_DOUBLE
(
"ADC2 Mute Switch"
,
PCM3168A_ADC_MUTE
,
2
,
3
,
1
,
0
),
SOC_DOUBLE
(
"ADC3 Mute Switch"
,
PCM3168A_ADC_MUTE
,
4
,
5
,
1
,
0
),
SOC_DOUBLE_STS
(
"ADC1 Overflow Flag"
,
PCM3168A_ADC_OV
,
0
,
1
,
1
,
0
),
SOC_DOUBLE_STS
(
"ADC2 Overflow Flag"
,
PCM3168A_ADC_OV
,
2
,
3
,
1
,
0
),
SOC_DOUBLE_STS
(
"ADC3 Overflow Flag"
,
PCM3168A_ADC_OV
,
4
,
5
,
1
,
0
),
SOC_ENUM
(
"ADC Volume Control Type"
,
pcm3168a_adc_volume_type
),
SOC_ENUM
(
"ADC Volume Rate Multiplier"
,
pcm3168a_adc_att_mult
),
SOC_ENUM
(
"ADC Overflow Flag Polarity"
,
pcm3168a_adc_ov_pol
),
SOC_SINGLE_RANGE_TLV
(
"Master Capture Volume"
,
PCM3168A_ADC_VOL_MASTER
,
0
,
14
,
255
,
0
,
pcm3168a_adc_tlv
),
SOC_DOUBLE_R_RANGE_TLV
(
"ADC1 Capture Volume"
,
PCM3168A_ADC_VOL_CHAN_START
,
PCM3168A_ADC_VOL_CHAN_START
+
1
,
0
,
14
,
255
,
0
,
pcm3168a_adc_tlv
),
SOC_DOUBLE_R_RANGE_TLV
(
"ADC2 Capture Volume"
,
PCM3168A_ADC_VOL_CHAN_START
+
2
,
PCM3168A_ADC_VOL_CHAN_START
+
3
,
0
,
14
,
255
,
0
,
pcm3168a_adc_tlv
),
SOC_DOUBLE_R_RANGE_TLV
(
"ADC3 Capture Volume"
,
PCM3168A_ADC_VOL_CHAN_START
+
4
,
PCM3168A_ADC_VOL_CHAN_START
+
5
,
0
,
14
,
255
,
0
,
pcm3168a_adc_tlv
)
};
static
const
struct
snd_soc_dapm_widget
pcm3168a_dapm_widgets
[]
=
{
SND_SOC_DAPM_DAC
(
"DAC1"
,
"Playback"
,
PCM3168A_DAC_OP_FLT
,
PCM3168A_DAC_OPEDA_SHIFT
,
1
),
SND_SOC_DAPM_DAC
(
"DAC2"
,
"Playback"
,
PCM3168A_DAC_OP_FLT
,
PCM3168A_DAC_OPEDA_SHIFT
+
1
,
1
),
SND_SOC_DAPM_DAC
(
"DAC3"
,
"Playback"
,
PCM3168A_DAC_OP_FLT
,
PCM3168A_DAC_OPEDA_SHIFT
+
2
,
1
),
SND_SOC_DAPM_DAC
(
"DAC4"
,
"Playback"
,
PCM3168A_DAC_OP_FLT
,
PCM3168A_DAC_OPEDA_SHIFT
+
3
,
1
),
SND_SOC_DAPM_OUTPUT
(
"AOUT1L"
),
SND_SOC_DAPM_OUTPUT
(
"AOUT1R"
),
SND_SOC_DAPM_OUTPUT
(
"AOUT2L"
),
SND_SOC_DAPM_OUTPUT
(
"AOUT2R"
),
SND_SOC_DAPM_OUTPUT
(
"AOUT3L"
),
SND_SOC_DAPM_OUTPUT
(
"AOUT3R"
),
SND_SOC_DAPM_OUTPUT
(
"AOUT4L"
),
SND_SOC_DAPM_OUTPUT
(
"AOUT4R"
),
SND_SOC_DAPM_ADC
(
"ADC1"
,
"Capture"
,
PCM3168A_ADC_PWR_HPFB
,
PCM3168A_ADC_PSVAD_SHIFT
,
1
),
SND_SOC_DAPM_ADC
(
"ADC2"
,
"Capture"
,
PCM3168A_ADC_PWR_HPFB
,
PCM3168A_ADC_PSVAD_SHIFT
+
1
,
1
),
SND_SOC_DAPM_ADC
(
"ADC3"
,
"Capture"
,
PCM3168A_ADC_PWR_HPFB
,
PCM3168A_ADC_PSVAD_SHIFT
+
2
,
1
),
SND_SOC_DAPM_INPUT
(
"AIN1L"
),
SND_SOC_DAPM_INPUT
(
"AIN1R"
),
SND_SOC_DAPM_INPUT
(
"AIN2L"
),
SND_SOC_DAPM_INPUT
(
"AIN2R"
),
SND_SOC_DAPM_INPUT
(
"AIN3L"
),
SND_SOC_DAPM_INPUT
(
"AIN3R"
)
};
static
const
struct
snd_soc_dapm_route
pcm3168a_dapm_routes
[]
=
{
/* Playback */
{
"AOUT1L"
,
NULL
,
"DAC1"
},
{
"AOUT1R"
,
NULL
,
"DAC1"
},
{
"AOUT2L"
,
NULL
,
"DAC2"
},
{
"AOUT2R"
,
NULL
,
"DAC2"
},
{
"AOUT3L"
,
NULL
,
"DAC3"
},
{
"AOUT3R"
,
NULL
,
"DAC3"
},
{
"AOUT4L"
,
NULL
,
"DAC4"
},
{
"AOUT4R"
,
NULL
,
"DAC4"
},
/* Capture */
{
"ADC1"
,
NULL
,
"AIN1L"
},
{
"ADC1"
,
NULL
,
"AIN1R"
},
{
"ADC2"
,
NULL
,
"AIN2L"
},
{
"ADC2"
,
NULL
,
"AIN2R"
},
{
"ADC3"
,
NULL
,
"AIN3L"
},
{
"ADC3"
,
NULL
,
"AIN3R"
}
};
static
unsigned
int
pcm3168a_scki_ratios
[]
=
{
768
,
512
,
384
,
256
,
192
,
128
};
#define PCM3168A_NUM_SCKI_RATIOS_DAC ARRAY_SIZE(pcm3168a_scki_ratios)
#define PCM3168A_NUM_SCKI_RATIOS_ADC (ARRAY_SIZE(pcm3168a_scki_ratios) - 2)
#define PCM1368A_MAX_SYSCLK 36864000
static
int
pcm3168a_reset
(
struct
pcm3168a_priv
*
pcm3168a
)
{
int
ret
;
ret
=
regmap_write
(
pcm3168a
->
regmap
,
PCM3168A_RST_SMODE
,
0
);
if
(
ret
)
return
ret
;
/* Internal reset is de-asserted after 3846 SCKI cycles */
msleep
(
DIV_ROUND_UP
(
3846
*
1000
,
pcm3168a
->
sysclk
));
return
regmap_write
(
pcm3168a
->
regmap
,
PCM3168A_RST_SMODE
,
PCM3168A_MRST_MASK
|
PCM3168A_SRST_MASK
);
}
static
int
pcm3168a_digital_mute
(
struct
snd_soc_dai
*
dai
,
int
mute
)
{
struct
snd_soc_codec
*
codec
=
dai
->
codec
;
struct
pcm3168a_priv
*
pcm3168a
=
snd_soc_codec_get_drvdata
(
codec
);
regmap_write
(
pcm3168a
->
regmap
,
PCM3168A_DAC_MUTE
,
mute
?
0xff
:
0
);
return
0
;
}
static
int
pcm3168a_set_dai_sysclk
(
struct
snd_soc_dai
*
dai
,
int
clk_id
,
unsigned
int
freq
,
int
dir
)
{
struct
pcm3168a_priv
*
pcm3168a
=
snd_soc_codec_get_drvdata
(
dai
->
codec
);
if
(
freq
>
PCM1368A_MAX_SYSCLK
)
return
-
EINVAL
;
pcm3168a
->
sysclk
=
freq
;
return
0
;
}
static
int
pcm3168a_set_dai_fmt
(
struct
snd_soc_dai
*
dai
,
unsigned
int
format
,
bool
dac
)
{
struct
snd_soc_codec
*
codec
=
dai
->
codec
;
struct
pcm3168a_priv
*
pcm3168a
=
snd_soc_codec_get_drvdata
(
codec
);
u32
fmt
,
reg
,
mask
,
shift
;
bool
master_mode
;
switch
(
format
&
SND_SOC_DAIFMT_FORMAT_MASK
)
{
case
SND_SOC_DAIFMT_LEFT_J
:
fmt
=
PCM3168A_FMT_LEFT_J
;
break
;
case
SND_SOC_DAIFMT_I2S
:
fmt
=
PCM3168A_FMT_I2S
;
break
;
case
SND_SOC_DAIFMT_RIGHT_J
:
fmt
=
PCM3168A_FMT_RIGHT_J
;
break
;
case
SND_SOC_DAIFMT_DSP_A
:
fmt
=
PCM3168A_FMT_DSP_A
;
break
;
case
SND_SOC_DAIFMT_DSP_B
:
fmt
=
PCM3168A_FMT_DSP_B
;
break
;
default:
dev_err
(
codec
->
dev
,
"unsupported dai format
\n
"
);
return
-
EINVAL
;
}
switch
(
format
&
SND_SOC_DAIFMT_MASTER_MASK
)
{
case
SND_SOC_DAIFMT_CBS_CFS
:
master_mode
=
false
;
break
;
case
SND_SOC_DAIFMT_CBM_CFM
:
master_mode
=
true
;
break
;
default:
dev_err
(
codec
->
dev
,
"unsupported master/slave mode
\n
"
);
return
-
EINVAL
;
}
switch
(
format
&
SND_SOC_DAIFMT_INV_MASK
)
{
case
SND_SOC_DAIFMT_NB_NF
:
break
;
default:
return
-
EINVAL
;
}
if
(
dac
)
{
reg
=
PCM3168A_DAC_PWR_MST_FMT
;
mask
=
PCM3168A_DAC_FMT_MASK
;
shift
=
PCM3168A_DAC_FMT_SHIFT
;
pcm3168a
->
dac_master_mode
=
master_mode
;
pcm3168a
->
dac_fmt
=
fmt
;
}
else
{
reg
=
PCM3168A_ADC_MST_FMT
;
mask
=
PCM3168A_ADC_FMTAD_MASK
;
shift
=
PCM3168A_ADC_FMTAD_SHIFT
;
pcm3168a
->
adc_master_mode
=
master_mode
;
pcm3168a
->
adc_fmt
=
fmt
;
}
regmap_update_bits
(
pcm3168a
->
regmap
,
reg
,
mask
,
fmt
<<
shift
);
return
0
;
}
static
int
pcm3168a_set_dai_fmt_dac
(
struct
snd_soc_dai
*
dai
,
unsigned
int
format
)
{
return
pcm3168a_set_dai_fmt
(
dai
,
format
,
true
);
}
static
int
pcm3168a_set_dai_fmt_adc
(
struct
snd_soc_dai
*
dai
,
unsigned
int
format
)
{
return
pcm3168a_set_dai_fmt
(
dai
,
format
,
false
);
}
static
int
pcm3168a_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
pcm3168a_priv
*
pcm3168a
=
snd_soc_codec_get_drvdata
(
codec
);
bool
tx
,
master_mode
;
u32
val
,
mask
,
shift
,
reg
;
unsigned
int
rate
,
channels
,
fmt
,
ratio
,
max_ratio
;
int
i
,
min_frame_size
;
snd_pcm_format_t
format
;
rate
=
params_rate
(
params
);
format
=
params_format
(
params
);
channels
=
params_channels
(
params
);
ratio
=
pcm3168a
->
sysclk
/
rate
;
tx
=
substream
->
stream
==
SNDRV_PCM_STREAM_PLAYBACK
;
if
(
tx
)
{
max_ratio
=
PCM3168A_NUM_SCKI_RATIOS_DAC
;
reg
=
PCM3168A_DAC_PWR_MST_FMT
;
mask
=
PCM3168A_DAC_MSDA_MASK
;
shift
=
PCM3168A_DAC_MSDA_SHIFT
;
master_mode
=
pcm3168a
->
dac_master_mode
;
fmt
=
pcm3168a
->
dac_fmt
;
}
else
{
max_ratio
=
PCM3168A_NUM_SCKI_RATIOS_ADC
;
reg
=
PCM3168A_ADC_MST_FMT
;
mask
=
PCM3168A_ADC_MSAD_MASK
;
shift
=
PCM3168A_ADC_MSAD_SHIFT
;
master_mode
=
pcm3168a
->
adc_master_mode
;
fmt
=
pcm3168a
->
adc_fmt
;
}
for
(
i
=
0
;
i
<
max_ratio
;
i
++
)
{
if
(
pcm3168a_scki_ratios
[
i
]
==
ratio
)
break
;
}
if
(
i
==
max_ratio
)
{
dev_err
(
codec
->
dev
,
"unsupported sysclk ratio
\n
"
);
return
-
EINVAL
;
}
min_frame_size
=
params_width
(
params
)
*
2
;
switch
(
min_frame_size
)
{
case
32
:
if
(
master_mode
||
(
fmt
!=
PCM3168A_FMT_RIGHT_J
))
{
dev_err
(
codec
->
dev
,
"32-bit frames are supported only for slave mode using right justified
\n
"
);
return
-
EINVAL
;
}
fmt
=
PCM3168A_FMT_RIGHT_J_16
;
break
;
case
48
:
if
(
master_mode
||
(
fmt
&
PCM3168A_FMT_DSP_MASK
))
{
dev_err
(
codec
->
dev
,
"48-bit frames not supported in master mode, or slave mode using DSP
\n
"
);
return
-
EINVAL
;
}
break
;
case
64
:
break
;
default:
dev_err
(
codec
->
dev
,
"unsupported frame size: %d
\n
"
,
min_frame_size
);
return
-
EINVAL
;
}
if
(
master_mode
)
val
=
((
i
+
1
)
<<
shift
);
else
val
=
0
;
regmap_update_bits
(
pcm3168a
->
regmap
,
reg
,
mask
,
val
);
if
(
tx
)
{
mask
=
PCM3168A_DAC_FMT_MASK
;
shift
=
PCM3168A_DAC_FMT_SHIFT
;
}
else
{
mask
=
PCM3168A_ADC_FMTAD_MASK
;
shift
=
PCM3168A_ADC_FMTAD_SHIFT
;
}
regmap_update_bits
(
pcm3168a
->
regmap
,
reg
,
mask
,
fmt
<<
shift
);
return
0
;
}
static
const
struct
snd_soc_dai_ops
pcm3168a_dac_dai_ops
=
{
.
set_fmt
=
pcm3168a_set_dai_fmt_dac
,
.
set_sysclk
=
pcm3168a_set_dai_sysclk
,
.
hw_params
=
pcm3168a_hw_params
,
.
digital_mute
=
pcm3168a_digital_mute
};
static
const
struct
snd_soc_dai_ops
pcm3168a_adc_dai_ops
=
{
.
set_fmt
=
pcm3168a_set_dai_fmt_adc
,
.
set_sysclk
=
pcm3168a_set_dai_sysclk
,
.
hw_params
=
pcm3168a_hw_params
};
static
struct
snd_soc_dai_driver
pcm3168a_dais
[]
=
{
{
.
name
=
"pcm3168a-dac"
,
.
playback
=
{
.
stream_name
=
"Playback"
,
.
channels_min
=
1
,
.
channels_max
=
8
,
.
rates
=
SNDRV_PCM_RATE_8000_192000
,
.
formats
=
PCM3168A_FORMATS
},
.
ops
=
&
pcm3168a_dac_dai_ops
},
{
.
name
=
"pcm3168a-adc"
,
.
capture
=
{
.
stream_name
=
"Capture"
,
.
channels_min
=
1
,
.
channels_max
=
6
,
.
rates
=
SNDRV_PCM_RATE_8000_96000
,
.
formats
=
PCM3168A_FORMATS
},
.
ops
=
&
pcm3168a_adc_dai_ops
},
};
static
const
struct
reg_default
pcm3168a_reg_default
[]
=
{
{
PCM3168A_RST_SMODE
,
PCM3168A_MRST_MASK
|
PCM3168A_SRST_MASK
},
{
PCM3168A_DAC_PWR_MST_FMT
,
0x00
},
{
PCM3168A_DAC_OP_FLT
,
0x00
},
{
PCM3168A_DAC_INV
,
0x00
},
{
PCM3168A_DAC_MUTE
,
0x00
},
{
PCM3168A_DAC_ZERO
,
0x00
},
{
PCM3168A_DAC_ATT_DEMP_ZF
,
0x00
},
{
PCM3168A_DAC_VOL_MASTER
,
0xff
},
{
PCM3168A_DAC_VOL_CHAN_START
,
0xff
},
{
PCM3168A_DAC_VOL_CHAN_START
+
1
,
0xff
},
{
PCM3168A_DAC_VOL_CHAN_START
+
2
,
0xff
},
{
PCM3168A_DAC_VOL_CHAN_START
+
3
,
0xff
},
{
PCM3168A_DAC_VOL_CHAN_START
+
4
,
0xff
},
{
PCM3168A_DAC_VOL_CHAN_START
+
5
,
0xff
},
{
PCM3168A_DAC_VOL_CHAN_START
+
6
,
0xff
},
{
PCM3168A_DAC_VOL_CHAN_START
+
7
,
0xff
},
{
PCM3168A_ADC_SMODE
,
0x00
},
{
PCM3168A_ADC_MST_FMT
,
0x00
},
{
PCM3168A_ADC_PWR_HPFB
,
0x00
},
{
PCM3168A_ADC_SEAD
,
0x00
},
{
PCM3168A_ADC_INV
,
0x00
},
{
PCM3168A_ADC_MUTE
,
0x00
},
{
PCM3168A_ADC_OV
,
0x00
},
{
PCM3168A_ADC_ATT_OVF
,
0x00
},
{
PCM3168A_ADC_VOL_MASTER
,
0xd3
},
{
PCM3168A_ADC_VOL_CHAN_START
,
0xd3
},
{
PCM3168A_ADC_VOL_CHAN_START
+
1
,
0xd3
},
{
PCM3168A_ADC_VOL_CHAN_START
+
2
,
0xd3
},
{
PCM3168A_ADC_VOL_CHAN_START
+
3
,
0xd3
},
{
PCM3168A_ADC_VOL_CHAN_START
+
4
,
0xd3
},
{
PCM3168A_ADC_VOL_CHAN_START
+
5
,
0xd3
}
};
static
bool
pcm3168a_readable_register
(
struct
device
*
dev
,
unsigned
int
reg
)
{
if
(
reg
>=
PCM3168A_RST_SMODE
)
return
true
;
else
return
false
;
}
static
bool
pcm3168a_volatile_register
(
struct
device
*
dev
,
unsigned
int
reg
)
{
switch
(
reg
)
{
case
PCM3168A_DAC_ZERO
:
case
PCM3168A_ADC_OV
:
return
true
;
default:
return
false
;
}
}
static
bool
pcm3168a_writeable_register
(
struct
device
*
dev
,
unsigned
int
reg
)
{
if
(
reg
<
PCM3168A_RST_SMODE
)
return
false
;
switch
(
reg
)
{
case
PCM3168A_DAC_ZERO
:
case
PCM3168A_ADC_OV
:
return
false
;
default:
return
true
;
}
}
const
struct
regmap_config
pcm3168a_regmap
=
{
.
reg_bits
=
8
,
.
val_bits
=
8
,
.
max_register
=
PCM3168A_ADC_VOL_CHAN_START
+
5
,
.
reg_defaults
=
pcm3168a_reg_default
,
.
num_reg_defaults
=
ARRAY_SIZE
(
pcm3168a_reg_default
),
.
readable_reg
=
pcm3168a_readable_register
,
.
volatile_reg
=
pcm3168a_volatile_register
,
.
writeable_reg
=
pcm3168a_writeable_register
,
.
cache_type
=
REGCACHE_FLAT
};
EXPORT_SYMBOL_GPL
(
pcm3168a_regmap
);
static
const
struct
snd_soc_codec_driver
pcm3168a_driver
=
{
.
idle_bias_off
=
true
,
.
controls
=
pcm3168a_snd_controls
,
.
num_controls
=
ARRAY_SIZE
(
pcm3168a_snd_controls
),
.
dapm_widgets
=
pcm3168a_dapm_widgets
,
.
num_dapm_widgets
=
ARRAY_SIZE
(
pcm3168a_dapm_widgets
),
.
dapm_routes
=
pcm3168a_dapm_routes
,
.
num_dapm_routes
=
ARRAY_SIZE
(
pcm3168a_dapm_routes
)
};
int
pcm3168a_probe
(
struct
device
*
dev
,
struct
regmap
*
regmap
)
{
struct
pcm3168a_priv
*
pcm3168a
;
int
ret
,
i
;
pcm3168a
=
devm_kzalloc
(
dev
,
sizeof
(
*
pcm3168a
),
GFP_KERNEL
);
if
(
pcm3168a
==
NULL
)
return
-
ENOMEM
;
dev_set_drvdata
(
dev
,
pcm3168a
);
pcm3168a
->
scki
=
devm_clk_get
(
dev
,
"scki"
);
if
(
IS_ERR
(
pcm3168a
->
scki
))
{
ret
=
PTR_ERR
(
pcm3168a
->
scki
);
if
(
ret
!=
-
EPROBE_DEFER
)
dev_err
(
dev
,
"failed to acquire clock 'scki': %d
\n
"
,
ret
);
return
ret
;
}
ret
=
clk_prepare_enable
(
pcm3168a
->
scki
);
if
(
ret
)
{
dev_err
(
dev
,
"Failed to enable mclk: %d
\n
"
,
ret
);
return
ret
;
}
pcm3168a
->
sysclk
=
clk_get_rate
(
pcm3168a
->
scki
);
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
pcm3168a
->
supplies
);
i
++
)
pcm3168a
->
supplies
[
i
].
supply
=
pcm3168a_supply_names
[
i
];
ret
=
devm_regulator_bulk_get
(
dev
,
ARRAY_SIZE
(
pcm3168a
->
supplies
),
pcm3168a
->
supplies
);
if
(
ret
)
{
if
(
ret
!=
-
EPROBE_DEFER
)
dev_err
(
dev
,
"failed to request supplies: %d
\n
"
,
ret
);
goto
err_clk
;
}
ret
=
regulator_bulk_enable
(
ARRAY_SIZE
(
pcm3168a
->
supplies
),
pcm3168a
->
supplies
);
if
(
ret
)
{
dev_err
(
dev
,
"failed to enable supplies: %d
\n
"
,
ret
);
goto
err_clk
;
}
pcm3168a
->
regmap
=
regmap
;
if
(
IS_ERR
(
pcm3168a
->
regmap
))
{
ret
=
PTR_ERR
(
pcm3168a
->
regmap
);
dev_err
(
dev
,
"failed to allocate regmap: %d
\n
"
,
ret
);
goto
err_regulator
;
}
ret
=
pcm3168a_reset
(
pcm3168a
);
if
(
ret
)
{
dev_err
(
dev
,
"Failed to reset device: %d
\n
"
,
ret
);
goto
err_regulator
;
}
pm_runtime_set_active
(
dev
);
pm_runtime_enable
(
dev
);
pm_runtime_idle
(
dev
);
ret
=
snd_soc_register_codec
(
dev
,
&
pcm3168a_driver
,
pcm3168a_dais
,
ARRAY_SIZE
(
pcm3168a_dais
));
if
(
ret
)
{
dev_err
(
dev
,
"failed to register codec: %d
\n
"
,
ret
);
goto
err_regulator
;
}
return
0
;
err_regulator:
regulator_bulk_disable
(
ARRAY_SIZE
(
pcm3168a
->
supplies
),
pcm3168a
->
supplies
);
err_clk:
clk_disable_unprepare
(
pcm3168a
->
scki
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
pcm3168a_probe
);
void
pcm3168a_remove
(
struct
device
*
dev
)
{
struct
pcm3168a_priv
*
pcm3168a
=
dev_get_drvdata
(
dev
);
snd_soc_unregister_codec
(
dev
);
pm_runtime_disable
(
dev
);
regulator_bulk_disable
(
ARRAY_SIZE
(
pcm3168a
->
supplies
),
pcm3168a
->
supplies
);
clk_disable_unprepare
(
pcm3168a
->
scki
);
}
EXPORT_SYMBOL_GPL
(
pcm3168a_remove
);
#ifdef CONFIG_PM
static
int
pcm3168a_rt_resume
(
struct
device
*
dev
)
{
struct
pcm3168a_priv
*
pcm3168a
=
dev_get_drvdata
(
dev
);
int
ret
;
ret
=
clk_prepare_enable
(
pcm3168a
->
scki
);
if
(
ret
)
{
dev_err
(
dev
,
"Failed to enable mclk: %d
\n
"
,
ret
);
return
ret
;
}
ret
=
regulator_bulk_enable
(
ARRAY_SIZE
(
pcm3168a
->
supplies
),
pcm3168a
->
supplies
);
if
(
ret
)
{
dev_err
(
dev
,
"Failed to enable supplies: %d
\n
"
,
ret
);
goto
err_clk
;
}
ret
=
pcm3168a_reset
(
pcm3168a
);
if
(
ret
)
{
dev_err
(
dev
,
"Failed to reset device: %d
\n
"
,
ret
);
goto
err_regulator
;
}
regcache_cache_only
(
pcm3168a
->
regmap
,
false
);
regcache_mark_dirty
(
pcm3168a
->
regmap
);
ret
=
regcache_sync
(
pcm3168a
->
regmap
);
if
(
ret
)
{
dev_err
(
dev
,
"Failed to sync regmap: %d
\n
"
,
ret
);
goto
err_regulator
;
}
return
0
;
err_regulator:
regulator_bulk_disable
(
ARRAY_SIZE
(
pcm3168a
->
supplies
),
pcm3168a
->
supplies
);
err_clk:
clk_disable_unprepare
(
pcm3168a
->
scki
);
return
ret
;
}
static
int
pcm3168a_rt_suspend
(
struct
device
*
dev
)
{
struct
pcm3168a_priv
*
pcm3168a
=
dev_get_drvdata
(
dev
);
regcache_cache_only
(
pcm3168a
->
regmap
,
true
);
regulator_bulk_disable
(
ARRAY_SIZE
(
pcm3168a
->
supplies
),
pcm3168a
->
supplies
);
clk_disable_unprepare
(
pcm3168a
->
scki
);
return
0
;
}
#endif
const
struct
dev_pm_ops
pcm3168a_pm_ops
=
{
SET_RUNTIME_PM_OPS
(
pcm3168a_rt_suspend
,
pcm3168a_rt_resume
,
NULL
)
};
EXPORT_SYMBOL_GPL
(
pcm3168a_pm_ops
);
MODULE_DESCRIPTION
(
"PCM3168A codec driver"
);
MODULE_AUTHOR
(
"Damien Horsley <Damien.Horsley@imgtec.com>"
);
MODULE_LICENSE
(
"GPL v2"
);
sound/soc/codecs/pcm3168a.h
0 → 100644
View file @
89c172e2
/*
* PCM3168A codec driver header
*
* Copyright (C) 2015 Imagination Technologies Ltd.
*
* Author: Damien Horsley <Damien.Horsley@imgtec.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*/
#ifndef __PCM3168A_H__
#define __PCM3168A_H__
extern
const
struct
dev_pm_ops
pcm3168a_pm_ops
;
extern
const
struct
regmap_config
pcm3168a_regmap
;
extern
int
pcm3168a_probe
(
struct
device
*
dev
,
struct
regmap
*
regmap
);
extern
void
pcm3168a_remove
(
struct
device
*
dev
);
#define PCM3168A_RST_SMODE 0x40
#define PCM3168A_MRST_MASK 0x80
#define PCM3168A_SRST_MASK 0x40
#define PCM3168A_DAC_SRDA_SHIFT 0
#define PCM3168A_DAC_SRDA_MASK 0x3
#define PCM3168A_DAC_PWR_MST_FMT 0x41
#define PCM3168A_DAC_PSMDA_SHIFT 7
#define PCM3168A_DAC_PSMDA_MASK 0x80
#define PCM3168A_DAC_MSDA_SHIFT 4
#define PCM3168A_DAC_MSDA_MASK 0x70
#define PCM3168A_DAC_FMT_SHIFT 0
#define PCM3168A_DAC_FMT_MASK 0xf
#define PCM3168A_DAC_OP_FLT 0x42
#define PCM3168A_DAC_OPEDA_SHIFT 4
#define PCM3168A_DAC_OPEDA_MASK 0xf0
#define PCM3168A_DAC_FLT_SHIFT 0
#define PCM3168A_DAC_FLT_MASK 0xf
#define PCM3168A_DAC_INV 0x43
#define PCM3168A_DAC_MUTE 0x44
#define PCM3168A_DAC_ZERO 0x45
#define PCM3168A_DAC_ATT_DEMP_ZF 0x46
#define PCM3168A_DAC_ATMDDA_MASK 0x80
#define PCM3168A_DAC_ATMDDA_SHIFT 7
#define PCM3168A_DAC_ATSPDA_MASK 0x40
#define PCM3168A_DAC_ATSPDA_SHIFT 6
#define PCM3168A_DAC_DEMP_SHIFT 4
#define PCM3168A_DAC_DEMP_MASK 0x30
#define PCM3168A_DAC_AZRO_SHIFT 1
#define PCM3168A_DAC_AZRO_MASK 0xe
#define PCM3168A_DAC_ZREV_MASK 0x1
#define PCM3168A_DAC_ZREV_SHIFT 0
#define PCM3168A_DAC_VOL_MASTER 0x47
#define PCM3168A_DAC_VOL_CHAN_START 0x48
#define PCM3168A_ADC_SMODE 0x50
#define PCM3168A_ADC_SRAD_SHIFT 0
#define PCM3168A_ADC_SRAD_MASK 0x3
#define PCM3168A_ADC_MST_FMT 0x51
#define PCM3168A_ADC_MSAD_SHIFT 4
#define PCM3168A_ADC_MSAD_MASK 0x70
#define PCM3168A_ADC_FMTAD_SHIFT 0
#define PCM3168A_ADC_FMTAD_MASK 0x7
#define PCM3168A_ADC_PWR_HPFB 0x52
#define PCM3168A_ADC_PSVAD_SHIFT 4
#define PCM3168A_ADC_PSVAD_MASK 0x70
#define PCM3168A_ADC_BYP_SHIFT 0
#define PCM3168A_ADC_BYP_MASK 0x7
#define PCM3168A_ADC_SEAD 0x53
#define PCM3168A_ADC_INV 0x54
#define PCM3168A_ADC_MUTE 0x55
#define PCM3168A_ADC_OV 0x56
#define PCM3168A_ADC_ATT_OVF 0x57
#define PCM3168A_ADC_ATMDAD_MASK 0x80
#define PCM3168A_ADC_ATMDAD_SHIFT 7
#define PCM3168A_ADC_ATSPAD_MASK 0x40
#define PCM3168A_ADC_ATSPAD_SHIFT 6
#define PCM3168A_ADC_OVFP_MASK 0x1
#define PCM3168A_ADC_OVFP_SHIFT 0
#define PCM3168A_ADC_VOL_MASTER 0x58
#define PCM3168A_ADC_VOL_CHAN_START 0x59
#endif
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