Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
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
Show 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 @@
.put = snd_soc_put_volsw, \
.private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \
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) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
.info = snd_soc_info_volsw, \
...
...
sound/soc/codecs/Kconfig
View file @
89c172e2
...
...
@@ -85,6 +85,8 @@ config SND_SOC_ALL_CODECS
select SND_SOC_PCM1681 if I2C
select SND_SOC_PCM1792A if SPI_MASTER
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_SPI if SPI_MASTER
select SND_SOC_RT286 if I2C
...
...
@@ -506,6 +508,21 @@ config SND_SOC_PCM1792A
config SND_SOC_PCM3008
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
tristate
...
...
sound/soc/codecs/Makefile
View file @
89c172e2
...
...
@@ -78,6 +78,9 @@ snd-soc-nau8825-objs := nau8825.o
snd-soc-pcm1681-objs
:=
pcm1681.o
snd-soc-pcm1792a-codec-objs
:=
pcm1792a.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-i2c-objs
:=
pcm512x-i2c.o
snd-soc-pcm512x-spi-objs
:=
pcm512x-spi.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_PCM1792A)
+=
snd-soc-pcm1792a-codec.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_I2C)
+=
snd-soc-pcm512x-i2c.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