Commit 4bfd5ba3 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'asoc/topic/rcar', 'asoc/topic/rockchip',...

Merge remote-tracking branches 'asoc/topic/rcar', 'asoc/topic/rockchip', 'asoc/topic/rt298', 'asoc/topic/rt5514' and 'asoc/topic/rt5616' into asoc-next
Renesas R-Car sound Renesas R-Car sound
=============================================
* Modules
=============================================
Renesas R-Car sound is constructed from below modules
(for Gen2 or later)
SCU : Sampling Rate Converter Unit
- SRC : Sampling Rate Converter
- CMD
- CTU : Channel Transfer Unit
- MIX : Mixer
- DVC : Digital Volume and Mute Function
SSIU : Serial Sound Interface Unit
SSI : Serial Sound Interface
See detail of each module's channels, connection, limitation on datasheet
=============================================
* Multi channel
=============================================
Multi channel is supported by Multi-SSI, or TDM-SSI.
Multi-SSI : 6ch case, you can use stereo x 3 SSI
TDM-SSI : 6ch case, you can use TDM
=============================================
* Enable/Disable each modules
=============================================
See datasheet to check SRC/CTU/MIX/DVC connect-limitation.
DT controls enabling/disabling module.
${LINUX}/arch/arm/boot/dts/r8a7790-lager.dts can be good example.
This is example of
Playback: [MEM] -> [SRC2] -> [DVC0] -> [SSIU0/SSI0] -> [codec]
Capture: [MEM] <- [DVC1] <- [SRC3] <- [SSIU1/SSI1] <- [codec]
&rcar_sound {
...
rcar_sound,dai {
dai0 {
playback = <&ssi0 &src2 &dvc0>;
capture = <&ssi1 &src3 &dvc1>;
};
};
};
You can use below.
${LINUX}/arch/arm/boot/dts/r8a7790.dts can be good example.
&src0 &ctu00 &mix0 &dvc0 &ssi0
&src1 &ctu01 &mix1 &dvc1 &ssi1
&src2 &ctu02 &ssi2
&src3 &ctu03 &ssi3
&src4 &ssi4
&src5 &ctu10 &ssi5
&src6 &ctu11 &ssi6
&src7 &ctu12 &ssi7
&src8 &ctu13 &ssi8
&src9 &ssi9
=============================================
* SRC (Sampling Rate Converter)
=============================================
[xx]Hz [yy]Hz
------> [SRC] ------>
SRC can convert [xx]Hz to [yy]Hz. Then, it has below 2 modes
Asynchronous mode: input data / output data are based on different clocks.
you can use this mode on Playback / Capture
Synchronous mode: input data / output data are based on same clocks.
This mode will be used if system doesn't have its input clock,
for example digital TV case.
you can use this mode on Playback
------------------
** Asynchronous mode
------------------
You need to use "renesas,rsrc-card" sound card for it.
example)
sound {
compatible = "renesas,rsrc-card";
...
/*
* SRC Asynchronous mode setting
* Playback:
* All input data will be converted to 48kHz
* Capture:
* Inputed 48kHz data will be converted to
* system specified Hz
*/
convert-rate = <48000>;
...
cpu {
sound-dai = <&rcar_sound>;
};
codec {
...
};
};
------------------
** Synchronous mode
------------------
> amixer set "SRC Out Rate" on
> aplay xxxx.wav
> amixer set "SRC Out Rate" 48000
> amixer set "SRC Out Rate" 44100
=============================================
* CTU (Channel Transfer Unit)
=============================================
[xx]ch [yy]ch
------> [CTU] -------->
CTU can convert [xx]ch to [yy]ch, or exchange outputed channel.
CTU conversion needs matrix settings.
For more detail information, see below
Renesas R-Car datasheet
- Sampling Rate Converter Unit (SCU)
- SCU Operation
- CMD Block
- Functional Blocks in CMD
Renesas R-Car datasheet
- Sampling Rate Converter Unit (SCU)
- Register Description
- CTUn Scale Value exx Register (CTUn_SVxxR)
${LINUX}/sound/soc/sh/rcar/ctu.c
- comment of header
You need to use "renesas,rsrc-card" sound card for it.
example)
sound {
compatible = "renesas,rsrc-card";
...
/*
* CTU setting
* All input data will be converted to 2ch
* as output data
*/
convert-channels = <2>;
...
cpu {
sound-dai = <&rcar_sound>;
};
codec {
...
};
};
Ex) Exchange output channel
Input -> Output
1ch -> 0ch
0ch -> 1ch
example of using matrix
output 0ch = (input 0ch x 0) + (input 1ch x 1)
output 1ch = (input 0ch x 1) + (input 1ch x 0)
amixer set "CTU Reset" on
amixer set "CTU Pass" 9,10
amixer set "CTU SV0" 0,4194304
amixer set "CTU SV1" 4194304,0
example of changing connection
amixer set "CTU Reset" on
amixer set "CTU Pass" 2,1
=============================================
* MIX (Mixer)
=============================================
MIX merges 2 sounds path. You can see 2 sound interface on system,
and these sounds will be merged by MIX.
aplay -D plughw:0,0 xxxx.wav &
aplay -D plughw:0,1 yyyy.wav
You need to use "renesas,rsrc-card" sound card for it.
Ex)
[MEM] -> [SRC1] -> [CTU02] -+-> [MIX0] -> [DVC0] -> [SSI0]
|
[MEM] -> [SRC2] -> [CTU03] -+
sound {
compatible = "renesas,rsrc-card";
...
cpu@0 {
sound-dai = <&rcar_sound 0>;
};
cpu@1 {
sound-dai = <&rcar_sound 1>;
};
codec {
...
};
};
&rcar_sound {
...
rcar_sound,dai {
dai0 {
playback = <&src1 &ctu02 &mix0 &dvc0 &ssi0>;
};
dai1 {
playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>;
};
};
};
=============================================
* DVC (Digital Volume and Mute Function)
=============================================
DVC controls Playback/Capture volume.
Playback Volume
amixer set "DVC Out" 100%
Capture Volume
amixer set "DVC In" 100%
Playback Mute
amixer set "DVC Out Mute" on
Capture Mute
amixer set "DVC In Mute" on
Volume Ramp
amixer set "DVC Out Ramp Up Rate" "0.125 dB/64 steps"
amixer set "DVC Out Ramp Down Rate" "0.125 dB/512 steps"
amixer set "DVC Out Ramp" on
aplay xxx.wav &
amixer set "DVC Out" 80% // Volume Down
amixer set "DVC Out" 100% // Volume Up
=============================================
* SSIU (Serial Sound Interface Unit)
=============================================
There is no DT settings for SSIU, because SSIU will be automatically
selected via SSI.
SSIU can avoid some under/over run error, because it has some buffer.
But you can't use it if SSI was PIO mode.
In DMA mode, you can select not to use SSIU by using "no-busif" on DT.
&ssi0 {
no-busif;
};
=============================================
* SSI (Serial Sound Interface)
=============================================
** PIO mode
You can use PIO mode which is for connection check by using.
Note: The system will drop non-SSI modules in PIO mode
even though if DT is selecting other modules.
&ssi0 {
pio-transfer
};
** DMA mode without SSIU
You can use DMA without SSIU.
Note: under/over run, or noise are likely to occur
&ssi0 {
no-busif;
};
** PIN sharing
Each SSI can share WS pin. It is based on platform.
This is example if SSI1 want to share WS pin with SSI0
&ssi1 {
shared-pin;
};
** Multi-SSI
You can use Multi-SSI.
This is example of SSI0/SSI1/SSI2 (= for 6ch)
&rcar_sound {
...
rcar_sound,dai {
dai0 {
playback = <&ssi0 &ssi1 &ssi2 &src0 &dvc0>;
};
};
};
** TDM-SSI
You can use TDM with SSI.
This is example of TDM 6ch.
Driver can automatically switches TDM <-> stereo mode in this case.
rsnd_tdm: sound {
compatible = "simple-audio-card";
...
simple-audio-card,cpu {
/* system can use TDM 6ch */
dai-tdm-slot-num = <6>;
sound-dai = <&rcar_sound>;
};
simple-audio-card,codec {
...
};
};
=============================================
Required properties: Required properties:
=============================================
- compatible : "renesas,rcar_sound-<soctype>", fallbacks - compatible : "renesas,rcar_sound-<soctype>", fallbacks
"renesas,rcar_sound-gen1" if generation1, and "renesas,rcar_sound-gen1" if generation1, and
"renesas,rcar_sound-gen2" if generation2 "renesas,rcar_sound-gen2" if generation2
...@@ -64,7 +395,10 @@ DAI subnode properties: ...@@ -64,7 +395,10 @@ DAI subnode properties:
- playback : list of playback modules - playback : list of playback modules
- capture : list of capture modules - capture : list of capture modules
=============================================
Example: Example:
=============================================
rcar_sound: sound@ec500000 { rcar_sound: sound@ec500000 {
#sound-dai-cells = <1>; #sound-dai-cells = <1>;
...@@ -250,7 +584,9 @@ rcar_sound: sound@ec500000 { ...@@ -250,7 +584,9 @@ rcar_sound: sound@ec500000 {
}; };
}; };
=============================================
Example: simple sound card Example: simple sound card
=============================================
rsnd_ak4643: sound { rsnd_ak4643: sound {
compatible = "simple-audio-card"; compatible = "simple-audio-card";
...@@ -290,7 +626,9 @@ Example: simple sound card ...@@ -290,7 +626,9 @@ Example: simple sound card
shared-pin; shared-pin;
}; };
=============================================
Example: simple sound card for TDM Example: simple sound card for TDM
=============================================
rsnd_tdm: sound { rsnd_tdm: sound {
compatible = "simple-audio-card"; compatible = "simple-audio-card";
...@@ -309,7 +647,9 @@ Example: simple sound card for TDM ...@@ -309,7 +647,9 @@ Example: simple sound card for TDM
}; };
}; };
=============================================
Example: simple sound card for Multi channel Example: simple sound card for Multi channel
=============================================
&rcar_sound { &rcar_sound {
pinctrl-0 = <&sound_pins &sound_clk_pins>; pinctrl-0 = <&sound_pins &sound_clk_pins>;
......
...@@ -30,6 +30,7 @@ Optional subnode properties: ...@@ -30,6 +30,7 @@ Optional subnode properties:
- frame-inversion : bool property. Add this if the - frame-inversion : bool property. Add this if the
dai-link uses frame clock inversion. dai-link uses frame clock inversion.
- convert-rate : platform specified sampling rate convert - convert-rate : platform specified sampling rate convert
- convert-channels : platform specified converted channel size (2 - 8 ch)
- audio-prefix : see audio-routing - audio-prefix : see audio-routing
- audio-routing : A list of the connections between audio components. - audio-routing : A list of the connections between audio components.
Each entry is a pair of strings, the first being the connection's sink, Each entry is a pair of strings, the first being the connection's sink,
......
...@@ -9,6 +9,7 @@ Required properties: ...@@ -9,6 +9,7 @@ Required properties:
- "rockchip,rk3066-i2s": for rk3066 - "rockchip,rk3066-i2s": for rk3066
- "rockchip,rk3188-i2s", "rockchip,rk3066-i2s": for rk3188 - "rockchip,rk3188-i2s", "rockchip,rk3066-i2s": for rk3188
- "rockchip,rk3288-i2s", "rockchip,rk3066-i2s": for rk3288 - "rockchip,rk3288-i2s", "rockchip,rk3066-i2s": for rk3288
- "rockchip,rk3399-i2s", "rockchip,rk3066-i2s": for rk3399
- reg: physical base address of the controller and length of memory mapped - reg: physical base address of the controller and length of memory mapped
region. region.
- interrupts: should contain the I2S interrupt. - interrupts: should contain the I2S interrupt.
......
...@@ -7,8 +7,12 @@ a fibre cable. ...@@ -7,8 +7,12 @@ a fibre cable.
Required properties: Required properties:
- compatible: should be one of the following: - compatible: should be one of the following:
- "rockchip,rk3288-spdif", "rockchip,rk3188-spdif" or - "rockchip,rk3066-spdif"
"rockchip,rk3066-spdif" - "rockchip,rk3188-spdif"
- "rockchip,rk3288-spdif"
- "rockchip,rk3366-spdif"
- "rockchip,rk3368-spdif"
- "rockchip,rk3399-spdif"
- reg: physical base address of the controller and length of memory mapped - reg: physical base address of the controller and length of memory mapped
region. region.
- interrupts: should contain the SPDIF interrupt. - interrupts: should contain the SPDIF interrupt.
......
RT5514 audio CODEC
This device supports I2C only.
Required properties:
- compatible : "realtek,rt5514".
- reg : The I2C address of the device.
Pins on the device (for linking into audio routes) for RT5514:
* DMIC1L
* DMIC1R
* DMIC2L
* DMIC2R
* AMICL
* AMICR
Example:
codec: rt5514@57 {
compatible = "realtek,rt5514";
reg = <0x57>;
};
...@@ -8,6 +8,12 @@ Required properties: ...@@ -8,6 +8,12 @@ Required properties:
- reg : The I2C address of the device. - reg : The I2C address of the device.
Optional properties:
- clocks: The phandle of the master clock to the CODEC.
- clock-names: Should be "mclk".
Pins on the device (for linking into audio routes) for RT5616: Pins on the device (for linking into audio routes) for RT5616:
* IN1P * IN1P
......
...@@ -1692,100 +1692,63 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, ...@@ -1692,100 +1692,63 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
EXPORT_SYMBOL_GPL(regmap_raw_write); EXPORT_SYMBOL_GPL(regmap_raw_write);
/** /**
* regmap_field_write(): Write a value to a single register field * regmap_field_update_bits_base():
* * Perform a read/modify/write cycle on the register field
* @field: Register field to write to * with change, async, force option
* @val: Value to be written
*
* A value of zero will be returned on success, a negative errno will
* be returned in error cases.
*/
int regmap_field_write(struct regmap_field *field, unsigned int val)
{
return regmap_update_bits(field->regmap, field->reg,
field->mask, val << field->shift);
}
EXPORT_SYMBOL_GPL(regmap_field_write);
/**
* regmap_field_update_bits(): Perform a read/modify/write cycle
* on the register field
* *
* @field: Register field to write to * @field: Register field to write to
* @mask: Bitmask to change * @mask: Bitmask to change
* @val: Value to be written * @val: Value to be written
* @change: Boolean indicating if a write was done
* @async: Boolean indicating asynchronously
* @force: Boolean indicating use force update
* *
* A value of zero will be returned on success, a negative errno will * A value of zero will be returned on success, a negative errno will
* be returned in error cases. * be returned in error cases.
*/ */
int regmap_field_update_bits(struct regmap_field *field, unsigned int mask, unsigned int val) int regmap_field_update_bits_base(struct regmap_field *field,
unsigned int mask, unsigned int val,
bool *change, bool async, bool force)
{ {
mask = (mask << field->shift) & field->mask; mask = (mask << field->shift) & field->mask;
return regmap_update_bits(field->regmap, field->reg, return regmap_update_bits_base(field->regmap, field->reg,
mask, val << field->shift); mask, val << field->shift,
change, async, force);
} }
EXPORT_SYMBOL_GPL(regmap_field_update_bits); EXPORT_SYMBOL_GPL(regmap_field_update_bits_base);
/** /**
* regmap_fields_write(): Write a value to a single register field with port ID * regmap_fields_update_bits_base():
* * Perform a read/modify/write cycle on the register field
* @field: Register field to write to * with change, async, force option
* @id: port ID
* @val: Value to be written
*
* A value of zero will be returned on success, a negative errno will
* be returned in error cases.
*/
int regmap_fields_write(struct regmap_field *field, unsigned int id,
unsigned int val)
{
if (id >= field->id_size)
return -EINVAL;
return regmap_update_bits(field->regmap,
field->reg + (field->id_offset * id),
field->mask, val << field->shift);
}
EXPORT_SYMBOL_GPL(regmap_fields_write);
int regmap_fields_force_write(struct regmap_field *field, unsigned int id,
unsigned int val)
{
if (id >= field->id_size)
return -EINVAL;
return regmap_write_bits(field->regmap,
field->reg + (field->id_offset * id),
field->mask, val << field->shift);
}
EXPORT_SYMBOL_GPL(regmap_fields_force_write);
/**
* regmap_fields_update_bits(): Perform a read/modify/write cycle
* on the register field
* *
* @field: Register field to write to * @field: Register field to write to
* @id: port ID * @id: port ID
* @mask: Bitmask to change * @mask: Bitmask to change
* @val: Value to be written * @val: Value to be written
* @change: Boolean indicating if a write was done
* @async: Boolean indicating asynchronously
* @force: Boolean indicating use force update
* *
* A value of zero will be returned on success, a negative errno will * A value of zero will be returned on success, a negative errno will
* be returned in error cases. * be returned in error cases.
*/ */
int regmap_fields_update_bits(struct regmap_field *field, unsigned int id, int regmap_fields_update_bits_base(struct regmap_field *field, unsigned int id,
unsigned int mask, unsigned int val) unsigned int mask, unsigned int val,
bool *change, bool async, bool force)
{ {
if (id >= field->id_size) if (id >= field->id_size)
return -EINVAL; return -EINVAL;
mask = (mask << field->shift) & field->mask; mask = (mask << field->shift) & field->mask;
return regmap_update_bits(field->regmap, return regmap_update_bits_base(field->regmap,
field->reg + (field->id_offset * id), field->reg + (field->id_offset * id),
mask, val << field->shift); mask, val << field->shift,
change, async, force);
} }
EXPORT_SYMBOL_GPL(regmap_fields_update_bits); EXPORT_SYMBOL_GPL(regmap_fields_update_bits_base);
/* /*
* regmap_bulk_write(): Write multiple registers to the device * regmap_bulk_write(): Write multiple registers to the device
...@@ -2653,76 +2616,36 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, ...@@ -2653,76 +2616,36 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
} }
/** /**
* regmap_update_bits: Perform a read/modify/write cycle on the register map * regmap_update_bits_base:
* * Perform a read/modify/write cycle on the
* @map: Register map to update * register map with change, async, force option
* @reg: Register to update
* @mask: Bitmask to change
* @val: New value for bitmask
*
* Returns zero for success, a negative number on error.
*/
int regmap_update_bits(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val)
{
int ret;
map->lock(map->lock_arg);
ret = _regmap_update_bits(map, reg, mask, val, NULL, false);
map->unlock(map->lock_arg);
return ret;
}
EXPORT_SYMBOL_GPL(regmap_update_bits);
/**
* regmap_write_bits: Perform a read/modify/write cycle on the register map
*
* @map: Register map to update
* @reg: Register to update
* @mask: Bitmask to change
* @val: New value for bitmask
*
* Returns zero for success, a negative number on error.
*/
int regmap_write_bits(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val)
{
int ret;
map->lock(map->lock_arg);
ret = _regmap_update_bits(map, reg, mask, val, NULL, true);
map->unlock(map->lock_arg);
return ret;
}
EXPORT_SYMBOL_GPL(regmap_write_bits);
/**
* regmap_update_bits_async: Perform a read/modify/write cycle on the register
* map asynchronously
* *
* @map: Register map to update * @map: Register map to update
* @reg: Register to update * @reg: Register to update
* @mask: Bitmask to change * @mask: Bitmask to change
* @val: New value for bitmask * @val: New value for bitmask
* @change: Boolean indicating if a write was done
* @async: Boolean indicating asynchronously
* @force: Boolean indicating use force update
* *
* if async was true,
* With most buses the read must be done synchronously so this is most * With most buses the read must be done synchronously so this is most
* useful for devices with a cache which do not need to interact with * useful for devices with a cache which do not need to interact with
* the hardware to determine the current register value. * the hardware to determine the current register value.
* *
* Returns zero for success, a negative number on error. * Returns zero for success, a negative number on error.
*/ */
int regmap_update_bits_async(struct regmap *map, unsigned int reg, int regmap_update_bits_base(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val) unsigned int mask, unsigned int val,
bool *change, bool async, bool force)
{ {
int ret; int ret;
map->lock(map->lock_arg); map->lock(map->lock_arg);
map->async = true; map->async = async;
ret = _regmap_update_bits(map, reg, mask, val, NULL, false); ret = _regmap_update_bits(map, reg, mask, val, change, force);
map->async = false; map->async = false;
...@@ -2730,69 +2653,30 @@ int regmap_update_bits_async(struct regmap *map, unsigned int reg, ...@@ -2730,69 +2653,30 @@ int regmap_update_bits_async(struct regmap *map, unsigned int reg,
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(regmap_update_bits_async); EXPORT_SYMBOL_GPL(regmap_update_bits_base);
/**
* regmap_update_bits_check: Perform a read/modify/write cycle on the
* register map and report if updated
*
* @map: Register map to update
* @reg: Register to update
* @mask: Bitmask to change
* @val: New value for bitmask
* @change: Boolean indicating if a write was done
*
* Returns zero for success, a negative number on error.
*/
int regmap_update_bits_check(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val,
bool *change)
{
int ret;
map->lock(map->lock_arg);
ret = _regmap_update_bits(map, reg, mask, val, change, false);
map->unlock(map->lock_arg);
return ret;
}
EXPORT_SYMBOL_GPL(regmap_update_bits_check);
/** /**
* regmap_update_bits_check_async: Perform a read/modify/write cycle on the * regmap_write_bits: Perform a read/modify/write cycle on the register map
* register map asynchronously and report if
* updated
* *
* @map: Register map to update * @map: Register map to update
* @reg: Register to update * @reg: Register to update
* @mask: Bitmask to change * @mask: Bitmask to change
* @val: New value for bitmask * @val: New value for bitmask
* @change: Boolean indicating if a write was done
*
* With most buses the read must be done synchronously so this is most
* useful for devices with a cache which do not need to interact with
* the hardware to determine the current register value.
* *
* Returns zero for success, a negative number on error. * Returns zero for success, a negative number on error.
*/ */
int regmap_update_bits_check_async(struct regmap *map, unsigned int reg, int regmap_write_bits(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val, unsigned int mask, unsigned int val)
bool *change)
{ {
int ret; int ret;
map->lock(map->lock_arg); map->lock(map->lock_arg);
ret = _regmap_update_bits(map, reg, mask, val, NULL, true);
map->async = true;
ret = _regmap_update_bits(map, reg, mask, val, change, false);
map->async = false;
map->unlock(map->lock_arg); map->unlock(map->lock_arg);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(regmap_update_bits_check_async); EXPORT_SYMBOL_GPL(regmap_write_bits);
void regmap_async_complete_cb(struct regmap_async *async, int ret) void regmap_async_complete_cb(struct regmap_async *async, int ret)
{ {
......
...@@ -65,6 +65,33 @@ struct reg_sequence { ...@@ -65,6 +65,33 @@ struct reg_sequence {
unsigned int delay_us; unsigned int delay_us;
}; };
#define regmap_update_bits(map, reg, mask, val) \
regmap_update_bits_base(map, reg, mask, val, NULL, false, false)
#define regmap_update_bits_async(map, reg, mask, val)\
regmap_update_bits_base(map, reg, mask, val, NULL, true, false)
#define regmap_update_bits_check(map, reg, mask, val, change)\
regmap_update_bits_base(map, reg, mask, val, change, false, false)
#define regmap_update_bits_check_async(map, reg, mask, val, change)\
regmap_update_bits_base(map, reg, mask, val, change, true, false)
#define regmap_field_write(field, val) \
regmap_field_update_bits_base(field, ~0, val, NULL, false, false)
#define regmap_field_force_write(field, val) \
regmap_field_update_bits_base(field, ~0, val, NULL, false, true)
#define regmap_field_update_bits(field, mask, val)\
regmap_field_update_bits_base(field, mask, val, NULL, false, false)
#define regmap_field_force_update_bits(field, mask, val) \
regmap_field_update_bits_base(field, mask, val, NULL, false, true)
#define regmap_fields_write(field, id, val) \
regmap_fields_update_bits_base(field, id, ~0, val, NULL, false, false)
#define regmap_fields_force_write(field, id, val) \
regmap_fields_update_bits_base(field, id, ~0, val, NULL, false, true)
#define regmap_fields_update_bits(field, id, mask, val)\
regmap_fields_update_bits_base(field, id, mask, val, NULL, false, false)
#define regmap_fields_force_update_bits(field, id, mask, val) \
regmap_fields_update_bits_base(field, id, mask, val, NULL, false, true)
#ifdef CONFIG_REGMAP #ifdef CONFIG_REGMAP
enum regmap_endian { enum regmap_endian {
...@@ -691,18 +718,11 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, ...@@ -691,18 +718,11 @@ int regmap_raw_read(struct regmap *map, unsigned int reg,
void *val, size_t val_len); void *val, size_t val_len);
int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
size_t val_count); size_t val_count);
int regmap_update_bits(struct regmap *map, unsigned int reg, int regmap_update_bits_base(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val); unsigned int mask, unsigned int val,
bool *change, bool async, bool force);
int regmap_write_bits(struct regmap *map, unsigned int reg, int regmap_write_bits(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val); unsigned int mask, unsigned int val);
int regmap_update_bits_async(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val);
int regmap_update_bits_check(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val,
bool *change);
int regmap_update_bits_check_async(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val,
bool *change);
int regmap_get_val_bytes(struct regmap *map); int regmap_get_val_bytes(struct regmap *map);
int regmap_get_max_register(struct regmap *map); int regmap_get_max_register(struct regmap *map);
int regmap_get_reg_stride(struct regmap *map); int regmap_get_reg_stride(struct regmap *map);
...@@ -770,18 +790,14 @@ struct regmap_field *devm_regmap_field_alloc(struct device *dev, ...@@ -770,18 +790,14 @@ struct regmap_field *devm_regmap_field_alloc(struct device *dev,
void devm_regmap_field_free(struct device *dev, struct regmap_field *field); void devm_regmap_field_free(struct device *dev, struct regmap_field *field);
int regmap_field_read(struct regmap_field *field, unsigned int *val); int regmap_field_read(struct regmap_field *field, unsigned int *val);
int regmap_field_write(struct regmap_field *field, unsigned int val); int regmap_field_update_bits_base(struct regmap_field *field,
int regmap_field_update_bits(struct regmap_field *field, unsigned int mask, unsigned int val,
unsigned int mask, unsigned int val); bool *change, bool async, bool force);
int regmap_fields_write(struct regmap_field *field, unsigned int id,
unsigned int val);
int regmap_fields_force_write(struct regmap_field *field, unsigned int id,
unsigned int val);
int regmap_fields_read(struct regmap_field *field, unsigned int id, int regmap_fields_read(struct regmap_field *field, unsigned int id,
unsigned int *val); unsigned int *val);
int regmap_fields_update_bits(struct regmap_field *field, unsigned int id, int regmap_fields_update_bits_base(struct regmap_field *field, unsigned int id,
unsigned int mask, unsigned int val); unsigned int mask, unsigned int val,
bool *change, bool async, bool force);
/** /**
* Description of an IRQ for the generic regmap irq_chip. * Description of an IRQ for the generic regmap irq_chip.
...@@ -937,8 +953,9 @@ static inline int regmap_bulk_read(struct regmap *map, unsigned int reg, ...@@ -937,8 +953,9 @@ static inline int regmap_bulk_read(struct regmap *map, unsigned int reg,
return -EINVAL; return -EINVAL;
} }
static inline int regmap_update_bits(struct regmap *map, unsigned int reg, static inline int regmap_update_bits_base(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val) unsigned int mask, unsigned int val,
bool *change, bool async, bool force)
{ {
WARN_ONCE(1, "regmap API is disabled"); WARN_ONCE(1, "regmap API is disabled");
return -EINVAL; return -EINVAL;
...@@ -951,28 +968,18 @@ static inline int regmap_write_bits(struct regmap *map, unsigned int reg, ...@@ -951,28 +968,18 @@ static inline int regmap_write_bits(struct regmap *map, unsigned int reg,
return -EINVAL; return -EINVAL;
} }
static inline int regmap_update_bits_async(struct regmap *map, static inline int regmap_field_update_bits_base(struct regmap_field *field,
unsigned int reg, unsigned int mask, unsigned int val,
unsigned int mask, unsigned int val) bool *change, bool async, bool force)
{ {
WARN_ONCE(1, "regmap API is disabled"); WARN_ONCE(1, "regmap API is disabled");
return -EINVAL; return -EINVAL;
} }
static inline int regmap_update_bits_check(struct regmap *map, static inline int regmap_fields_update_bits_base(struct regmap_field *field,
unsigned int reg, unsigned int id,
unsigned int mask, unsigned int val, unsigned int mask, unsigned int val,
bool *change) bool *change, bool async, bool force)
{
WARN_ONCE(1, "regmap API is disabled");
return -EINVAL;
}
static inline int regmap_update_bits_check_async(struct regmap *map,
unsigned int reg,
unsigned int mask,
unsigned int val,
bool *change)
{ {
WARN_ONCE(1, "regmap API is disabled"); WARN_ONCE(1, "regmap API is disabled");
return -EINVAL; return -EINVAL;
......
...@@ -98,6 +98,7 @@ config SND_SOC_ALL_CODECS ...@@ -98,6 +98,7 @@ config SND_SOC_ALL_CODECS
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
select SND_SOC_RT298 if I2C select SND_SOC_RT298 if I2C
select SND_SOC_RT5514 if I2C
select SND_SOC_RT5616 if I2C select SND_SOC_RT5616 if I2C
select SND_SOC_RT5631 if I2C select SND_SOC_RT5631 if I2C
select SND_SOC_RT5640 if I2C select SND_SOC_RT5640 if I2C
...@@ -501,6 +502,7 @@ config SND_SOC_ICS43432 ...@@ -501,6 +502,7 @@ config SND_SOC_ICS43432
config SND_SOC_INNO_RK3036 config SND_SOC_INNO_RK3036
tristate "Inno codec driver for RK3036 SoC" tristate "Inno codec driver for RK3036 SoC"
select REGMAP_MMIO
config SND_SOC_ISABELLE config SND_SOC_ISABELLE
tristate tristate
...@@ -590,6 +592,7 @@ config SND_SOC_PCM512x_SPI ...@@ -590,6 +592,7 @@ config SND_SOC_PCM512x_SPI
config SND_SOC_RL6231 config SND_SOC_RL6231
tristate tristate
default y if SND_SOC_RT5514=y
default y if SND_SOC_RT5616=y default y if SND_SOC_RT5616=y
default y if SND_SOC_RT5640=y default y if SND_SOC_RT5640=y
default y if SND_SOC_RT5645=y default y if SND_SOC_RT5645=y
...@@ -597,6 +600,7 @@ config SND_SOC_RL6231 ...@@ -597,6 +600,7 @@ config SND_SOC_RL6231
default y if SND_SOC_RT5659=y default y if SND_SOC_RT5659=y
default y if SND_SOC_RT5670=y default y if SND_SOC_RT5670=y
default y if SND_SOC_RT5677=y default y if SND_SOC_RT5677=y
default m if SND_SOC_RT5514=m
default m if SND_SOC_RT5616=m default m if SND_SOC_RT5616=m
default m if SND_SOC_RT5640=m default m if SND_SOC_RT5640=m
default m if SND_SOC_RT5645=m default m if SND_SOC_RT5645=m
...@@ -620,9 +624,12 @@ config SND_SOC_RT298 ...@@ -620,9 +624,12 @@ config SND_SOC_RT298
tristate tristate
depends on I2C depends on I2C
config SND_SOC_RT5616 config SND_SOC_RT5514
tristate tristate
config SND_SOC_RT5616
tristate "Realtek RT5616 CODEC"
config SND_SOC_RT5631 config SND_SOC_RT5631
tristate "Realtek ALC5631/RT5631 CODEC" tristate "Realtek ALC5631/RT5631 CODEC"
depends on I2C depends on I2C
......
...@@ -96,6 +96,7 @@ snd-soc-rl6231-objs := rl6231.o ...@@ -96,6 +96,7 @@ snd-soc-rl6231-objs := rl6231.o
snd-soc-rl6347a-objs := rl6347a.o snd-soc-rl6347a-objs := rl6347a.o
snd-soc-rt286-objs := rt286.o snd-soc-rt286-objs := rt286.o
snd-soc-rt298-objs := rt298.o snd-soc-rt298-objs := rt298.o
snd-soc-rt5514-objs := rt5514.o
snd-soc-rt5616-objs := rt5616.o snd-soc-rt5616-objs := rt5616.o
snd-soc-rt5631-objs := rt5631.o snd-soc-rt5631-objs := rt5631.o
snd-soc-rt5640-objs := rt5640.o snd-soc-rt5640-objs := rt5640.o
...@@ -304,6 +305,7 @@ obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o ...@@ -304,6 +305,7 @@ obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o
obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o
obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o
obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o
obj-$(CONFIG_SND_SOC_RT5514) += snd-soc-rt5514.o
obj-$(CONFIG_SND_SOC_RT5616) += snd-soc-rt5616.o obj-$(CONFIG_SND_SOC_RT5616) += snd-soc-rt5616.o
obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o
......
...@@ -1224,7 +1224,12 @@ static int rt298_i2c_probe(struct i2c_client *i2c, ...@@ -1224,7 +1224,12 @@ static int rt298_i2c_probe(struct i2c_client *i2c,
regmap_write(rt298->regmap, RT298_MISC_CTRL1, 0x0000); regmap_write(rt298->regmap, RT298_MISC_CTRL1, 0x0000);
regmap_update_bits(rt298->regmap, regmap_update_bits(rt298->regmap,
RT298_WIND_FILTER_CTRL, 0x0082, 0x0082); RT298_WIND_FILTER_CTRL, 0x0082, 0x0082);
regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x2);
regmap_write(rt298->regmap, RT298_UNSOLICITED_INLINE_CMD, 0x81);
regmap_write(rt298->regmap, RT298_UNSOLICITED_HP_OUT, 0x82);
regmap_write(rt298->regmap, RT298_UNSOLICITED_MIC1, 0x84);
regmap_update_bits(rt298->regmap, RT298_IRQ_FLAG_CTRL, 0x2, 0x2);
rt298->is_hp_in = -1; rt298->is_hp_in = -1;
if (rt298->i2c->irq) { if (rt298->i2c->irq) {
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#define RT298_HP_OUT 0x21 #define RT298_HP_OUT 0x21
#define RT298_MIXER_IN1 0x22 #define RT298_MIXER_IN1 0x22
#define RT298_MIXER_IN2 0x23 #define RT298_MIXER_IN2 0x23
#define RT298_INLINE_CMD 0x55
#define RT298_SET_PIN_SFT 6 #define RT298_SET_PIN_SFT 6
#define RT298_SET_PIN_ENABLE 0x40 #define RT298_SET_PIN_ENABLE 0x40
...@@ -124,6 +125,12 @@ ...@@ -124,6 +125,12 @@
VERB_CMD(AC_VERB_SET_COEF_INDEX, RT298_VENDOR_REGISTERS, 0) VERB_CMD(AC_VERB_SET_COEF_INDEX, RT298_VENDOR_REGISTERS, 0)
#define RT298_PROC_COEF\ #define RT298_PROC_COEF\
VERB_CMD(AC_VERB_SET_PROC_COEF, RT298_VENDOR_REGISTERS, 0) VERB_CMD(AC_VERB_SET_PROC_COEF, RT298_VENDOR_REGISTERS, 0)
#define RT298_UNSOLICITED_INLINE_CMD\
VERB_CMD(AC_VERB_SET_UNSOLICITED_ENABLE, RT298_INLINE_CMD, 0)
#define RT298_UNSOLICITED_HP_OUT\
VERB_CMD(AC_VERB_SET_UNSOLICITED_ENABLE, RT298_HP_OUT, 0)
#define RT298_UNSOLICITED_MIC1\
VERB_CMD(AC_VERB_SET_UNSOLICITED_ENABLE, RT298_MIC1, 0)
/* Index registers */ /* Index registers */
#define RT298_A_BIAS_CTRL1 0x01 #define RT298_A_BIAS_CTRL1 0x01
...@@ -148,6 +155,7 @@ ...@@ -148,6 +155,7 @@
#define RT298_DEPOP_CTRL2 0x67 #define RT298_DEPOP_CTRL2 0x67
#define RT298_DEPOP_CTRL3 0x68 #define RT298_DEPOP_CTRL3 0x68
#define RT298_DEPOP_CTRL4 0x69 #define RT298_DEPOP_CTRL4 0x69
#define RT298_IRQ_FLAG_CTRL 0x7c
/* SPDIF (0x06) */ /* SPDIF (0x06) */
#define RT298_SPDIF_SEL_SFT 0 #define RT298_SPDIF_SEL_SFT 0
......
This diff is collapsed.
/*
* rt5514.h -- RT5514 ALSA SoC audio driver
*
* Copyright 2015 Realtek Microelectronics
* Author: Oder Chiou <oder_chiou@realtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __RT5514_H__
#define __RT5514_H__
#define RT5514_DEVICE_ID 0x10ec5514
#define RT5514_RESET 0x2000
#define RT5514_PWR_ANA1 0x2004
#define RT5514_PWR_ANA2 0x2008
#define RT5514_I2S_CTRL1 0x2010
#define RT5514_I2S_CTRL2 0x2014
#define RT5514_VAD_CTRL6 0x2030
#define RT5514_EXT_VAD_CTRL 0x206c
#define RT5514_DIG_IO_CTRL 0x2070
#define RT5514_PAD_CTRL1 0x2080
#define RT5514_DMIC_DATA_CTRL 0x20a0
#define RT5514_DIG_SOURCE_CTRL 0x20a4
#define RT5514_SRC_CTRL 0x20ac
#define RT5514_DOWNFILTER2_CTRL1 0x20d0
#define RT5514_PLL_SOURCE_CTRL 0x2100
#define RT5514_CLK_CTRL1 0x2104
#define RT5514_CLK_CTRL2 0x2108
#define RT5514_PLL3_CALIB_CTRL1 0x2110
#define RT5514_PLL3_CALIB_CTRL5 0x2124
#define RT5514_DELAY_BUF_CTRL1 0x2140
#define RT5514_DELAY_BUF_CTRL3 0x2148
#define RT5514_DOWNFILTER0_CTRL1 0x2190
#define RT5514_DOWNFILTER0_CTRL2 0x2194
#define RT5514_DOWNFILTER0_CTRL3 0x2198
#define RT5514_DOWNFILTER1_CTRL1 0x21a0
#define RT5514_DOWNFILTER1_CTRL2 0x21a4
#define RT5514_DOWNFILTER1_CTRL3 0x21a8
#define RT5514_ANA_CTRL_LDO10 0x2200
#define RT5514_ANA_CTRL_LDO18_16 0x2204
#define RT5514_ANA_CTRL_ADC12 0x2210
#define RT5514_ANA_CTRL_ADC21 0x2214
#define RT5514_ANA_CTRL_ADC22 0x2218
#define RT5514_ANA_CTRL_ADC23 0x221c
#define RT5514_ANA_CTRL_MICBST 0x2220
#define RT5514_ANA_CTRL_ADCFED 0x2224
#define RT5514_ANA_CTRL_INBUF 0x2228
#define RT5514_ANA_CTRL_VREF 0x222c
#define RT5514_ANA_CTRL_PLL3 0x2240
#define RT5514_ANA_CTRL_PLL1_1 0x2260
#define RT5514_ANA_CTRL_PLL1_2 0x2264
#define RT5514_DMIC_LP_CTRL 0x2e00
#define RT5514_MISC_CTRL_DSP 0x2e04
#define RT5514_DSP_CTRL1 0x2f00
#define RT5514_DSP_CTRL3 0x2f08
#define RT5514_DSP_CTRL4 0x2f10
#define RT5514_VENDOR_ID1 0x2ff0
#define RT5514_VENDOR_ID2 0x2ff4
#define RT5514_DSP_MAPPING 0x18000000
/* RT5514_PWR_ANA1 (0x2004) */
#define RT5514_POW_LDO18_IN (0x1 << 5)
#define RT5514_POW_LDO18_IN_BIT 5
#define RT5514_POW_LDO18_ADC (0x1 << 4)
#define RT5514_POW_LDO18_ADC_BIT 4
#define RT5514_POW_LDO21 (0x1 << 3)
#define RT5514_POW_LDO21_BIT 3
#define RT5514_POW_BG_LDO18_IN (0x1 << 2)
#define RT5514_POW_BG_LDO18_IN_BIT 2
#define RT5514_POW_BG_LDO21 (0x1 << 1)
#define RT5514_POW_BG_LDO21_BIT 1
/* RT5514_PWR_ANA2 (0x2008) */
#define RT5514_POW_PLL1 (0x1 << 18)
#define RT5514_POW_PLL1_BIT 18
#define RT5514_POW_PLL1_LDO (0x1 << 16)
#define RT5514_POW_PLL1_LDO_BIT 16
#define RT5514_POW_BG_MBIAS (0x1 << 15)
#define RT5514_POW_BG_MBIAS_BIT 15
#define RT5514_POW_MBIAS (0x1 << 14)
#define RT5514_POW_MBIAS_BIT 14
#define RT5514_POW_VREF2 (0x1 << 13)
#define RT5514_POW_VREF2_BIT 13
#define RT5514_POW_VREF1 (0x1 << 12)
#define RT5514_POW_VREF1_BIT 12
#define RT5514_POWR_LDO16 (0x1 << 11)
#define RT5514_POWR_LDO16_BIT 11
#define RT5514_POWL_LDO16 (0x1 << 10)
#define RT5514_POWL_LDO16_BIT 10
#define RT5514_POW_ADC2 (0x1 << 9)
#define RT5514_POW_ADC2_BIT 9
#define RT5514_POW_INPUT_BUF (0x1 << 8)
#define RT5514_POW_INPUT_BUF_BIT 8
#define RT5514_POW_ADC1_R (0x1 << 7)
#define RT5514_POW_ADC1_R_BIT 7
#define RT5514_POW_ADC1_L (0x1 << 6)
#define RT5514_POW_ADC1_L_BIT 6
#define RT5514_POW2_BSTR (0x1 << 5)
#define RT5514_POW2_BSTR_BIT 5
#define RT5514_POW2_BSTL (0x1 << 4)
#define RT5514_POW2_BSTL_BIT 4
#define RT5514_POW_BSTR (0x1 << 3)
#define RT5514_POW_BSTR_BIT 3
#define RT5514_POW_BSTL (0x1 << 2)
#define RT5514_POW_BSTL_BIT 2
#define RT5514_POW_ADCFEDR (0x1 << 1)
#define RT5514_POW_ADCFEDR_BIT 1
#define RT5514_POW_ADCFEDL (0x1 << 0)
#define RT5514_POW_ADCFEDL_BIT 0
/* RT5514_I2S_CTRL1 (0x2010) */
#define RT5514_TDM_MODE (0x1 << 28)
#define RT5514_TDM_MODE_SFT 28
#define RT5514_I2S_LR_MASK (0x1 << 26)
#define RT5514_I2S_LR_SFT 26
#define RT5514_I2S_LR_NOR (0x0 << 26)
#define RT5514_I2S_LR_INV (0x1 << 26)
#define RT5514_I2S_BP_MASK (0x1 << 25)
#define RT5514_I2S_BP_SFT 25
#define RT5514_I2S_BP_NOR (0x0 << 25)
#define RT5514_I2S_BP_INV (0x1 << 25)
#define RT5514_I2S_DF_MASK (0x7 << 16)
#define RT5514_I2S_DF_SFT 16
#define RT5514_I2S_DF_I2S (0x0 << 16)
#define RT5514_I2S_DF_LEFT (0x1 << 16)
#define RT5514_I2S_DF_PCM_A (0x2 << 16)
#define RT5514_I2S_DF_PCM_B (0x3 << 16)
#define RT5514_TDMSLOT_SEL_RX_MASK (0x3 << 10)
#define RT5514_TDMSLOT_SEL_RX_SFT 10
#define RT5514_TDMSLOT_SEL_RX_4CH (0x1 << 10)
#define RT5514_CH_LEN_RX_MASK (0x3 << 8)
#define RT5514_CH_LEN_RX_SFT 8
#define RT5514_CH_LEN_RX_16 (0x0 << 8)
#define RT5514_CH_LEN_RX_20 (0x1 << 8)
#define RT5514_CH_LEN_RX_24 (0x2 << 8)
#define RT5514_CH_LEN_RX_32 (0x3 << 8)
#define RT5514_TDMSLOT_SEL_TX_MASK (0x3 << 6)
#define RT5514_TDMSLOT_SEL_TX_SFT 6
#define RT5514_TDMSLOT_SEL_TX_4CH (0x1 << 6)
#define RT5514_CH_LEN_TX_MASK (0x3 << 4)
#define RT5514_CH_LEN_TX_SFT 4
#define RT5514_CH_LEN_TX_16 (0x0 << 4)
#define RT5514_CH_LEN_TX_20 (0x1 << 4)
#define RT5514_CH_LEN_TX_24 (0x2 << 4)
#define RT5514_CH_LEN_TX_32 (0x3 << 4)
#define RT5514_I2S_DL_MASK (0x3 << 0)
#define RT5514_I2S_DL_SFT 0
#define RT5514_I2S_DL_16 (0x0 << 0)
#define RT5514_I2S_DL_20 (0x1 << 0)
#define RT5514_I2S_DL_24 (0x2 << 0)
#define RT5514_I2S_DL_8 (0x3 << 0)
/* RT5514_DIG_SOURCE_CTRL (0x20a4) */
#define RT5514_AD1_DMIC_INPUT_SEL (0x1 << 1)
#define RT5514_AD1_DMIC_INPUT_SEL_SFT 1
#define RT5514_AD0_DMIC_INPUT_SEL (0x1 << 0)
#define RT5514_AD0_DMIC_INPUT_SEL_SFT 0
/* RT5514_PLL_SOURCE_CTRL (0x2100) */
#define RT5514_PLL_1_SEL_MASK (0x7 << 12)
#define RT5514_PLL_1_SEL_SFT 12
#define RT5514_PLL_1_SEL_SCLK (0x3 << 12)
#define RT5514_PLL_1_SEL_MCLK (0x4 << 12)
/* RT5514_CLK_CTRL1 (0x2104) */
#define RT5514_CLK_AD_ANA1_EN (0x1 << 31)
#define RT5514_CLK_AD_ANA1_EN_BIT 31
#define RT5514_CLK_AD1_EN (0x1 << 24)
#define RT5514_CLK_AD1_EN_BIT 24
#define RT5514_CLK_AD0_EN (0x1 << 23)
#define RT5514_CLK_AD0_EN_BIT 23
#define RT5514_CLK_DMIC_OUT_SEL_MASK (0x7 << 8)
#define RT5514_CLK_DMIC_OUT_SEL_SFT 8
/* RT5514_CLK_CTRL2 (0x2108) */
#define RT5514_CLK_SYS_DIV_OUT_MASK (0x7 << 8)
#define RT5514_CLK_SYS_DIV_OUT_SFT 8
#define RT5514_SEL_ADC_OSR_MASK (0x7 << 4)
#define RT5514_SEL_ADC_OSR_SFT 4
#define RT5514_CLK_SYS_PRE_SEL_MASK (0x3 << 0)
#define RT5514_CLK_SYS_PRE_SEL_SFT 0
#define RT5514_CLK_SYS_PRE_SEL_MCLK (0x2 << 0)
#define RT5514_CLK_SYS_PRE_SEL_PLL (0x3 << 0)
/* RT5514_DOWNFILTER_CTRL (0x2190 0x2194 0x21a0 0x21a4) */
#define RT5514_AD_DMIC_MIX (0x1 << 11)
#define RT5514_AD_DMIC_MIX_BIT 11
#define RT5514_AD_AD_MIX (0x1 << 10)
#define RT5514_AD_AD_MIX_BIT 10
#define RT5514_AD_AD_MUTE (0x1 << 7)
#define RT5514_AD_AD_MUTE_BIT 7
#define RT5514_AD_GAIN_MASK (0x7f << 0)
#define RT5514_AD_GAIN_SFT 0
/* RT5514_ANA_CTRL_MICBST (0x2220) */
#define RT5514_SEL_BSTL_MASK (0xf << 4)
#define RT5514_SEL_BSTL_SFT 4
#define RT5514_SEL_BSTR_MASK (0xf << 0)
#define RT5514_SEL_BSTR_SFT 0
/* RT5514_ANA_CTRL_PLL1_1 (0x2260) */
#define RT5514_PLL_K_MAX 0x1f
#define RT5514_PLL_K_MASK (RT5514_PLL_K_MAX << 16)
#define RT5514_PLL_K_SFT 16
#define RT5514_PLL_N_MAX 0x1ff
#define RT5514_PLL_N_MASK (RT5514_PLL_N_MAX << 7)
#define RT5514_PLL_N_SFT 4
#define RT5514_PLL_M_MAX 0xf
#define RT5514_PLL_M_MASK (RT5514_PLL_M_MAX << 0)
#define RT5514_PLL_M_SFT 0
/* RT5514_ANA_CTRL_PLL1_2 (0x2264) */
#define RT5514_PLL_M_BP (0x1 << 2)
#define RT5514_PLL_M_BP_SFT 2
#define RT5514_PLL_K_BP (0x1 << 1)
#define RT5514_PLL_K_BP_SFT 1
#define RT5514_EN_LDO_PLL1 (0x1 << 0)
#define RT5514_EN_LDO_PLL1_BIT 0
#define RT5514_PLL_INP_MAX 40000000
#define RT5514_PLL_INP_MIN 256000
/* System Clock Source */
enum {
RT5514_SCLK_S_MCLK,
RT5514_SCLK_S_PLL1,
};
/* PLL1 Source */
enum {
RT5514_PLL1_S_MCLK,
RT5514_PLL1_S_BCLK,
};
struct rt5514_priv {
struct snd_soc_codec *codec;
struct regmap *i2c_regmap, *regmap;
int sysclk;
int sysclk_src;
int lrck;
int bclk;
int pll_src;
int pll_in;
int pll_out;
};
#endif /* __RT5514_H__ */
This diff is collapsed.
...@@ -440,11 +440,21 @@ static bool rockchip_i2s_precious_reg(struct device *dev, unsigned int reg) ...@@ -440,11 +440,21 @@ static bool rockchip_i2s_precious_reg(struct device *dev, unsigned int reg)
} }
} }
static const struct reg_default rockchip_i2s_reg_defaults[] = {
{0x00, 0x0000000f},
{0x04, 0x0000000f},
{0x08, 0x00071f1f},
{0x10, 0x001f0000},
{0x14, 0x01f00000},
};
static const struct regmap_config rockchip_i2s_regmap_config = { static const struct regmap_config rockchip_i2s_regmap_config = {
.reg_bits = 32, .reg_bits = 32,
.reg_stride = 4, .reg_stride = 4,
.val_bits = 32, .val_bits = 32,
.max_register = I2S_RXDR, .max_register = I2S_RXDR,
.reg_defaults = rockchip_i2s_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(rockchip_i2s_reg_defaults),
.writeable_reg = rockchip_i2s_wr_reg, .writeable_reg = rockchip_i2s_wr_reg,
.readable_reg = rockchip_i2s_rd_reg, .readable_reg = rockchip_i2s_rd_reg,
.volatile_reg = rockchip_i2s_volatile_reg, .volatile_reg = rockchip_i2s_volatile_reg,
...@@ -575,6 +585,9 @@ static int rockchip_i2s_remove(struct platform_device *pdev) ...@@ -575,6 +585,9 @@ static int rockchip_i2s_remove(struct platform_device *pdev)
static const struct of_device_id rockchip_i2s_match[] = { static const struct of_device_id rockchip_i2s_match[] = {
{ .compatible = "rockchip,rk3066-i2s", }, { .compatible = "rockchip,rk3066-i2s", },
{ .compatible = "rockchip,rk3188-i2s", },
{ .compatible = "rockchip,rk3288-i2s", },
{ .compatible = "rockchip,rk3399-i2s", },
{}, {},
}; };
......
...@@ -28,6 +28,7 @@ enum rk_spdif_type { ...@@ -28,6 +28,7 @@ enum rk_spdif_type {
RK_SPDIF_RK3066, RK_SPDIF_RK3066,
RK_SPDIF_RK3188, RK_SPDIF_RK3188,
RK_SPDIF_RK3288, RK_SPDIF_RK3288,
RK_SPDIF_RK3366,
}; };
#define RK3288_GRF_SOC_CON2 0x24c #define RK3288_GRF_SOC_CON2 0x24c
...@@ -45,16 +46,22 @@ struct rk_spdif_dev { ...@@ -45,16 +46,22 @@ struct rk_spdif_dev {
static const struct of_device_id rk_spdif_match[] = { static const struct of_device_id rk_spdif_match[] = {
{ .compatible = "rockchip,rk3066-spdif", { .compatible = "rockchip,rk3066-spdif",
.data = (void *) RK_SPDIF_RK3066 }, .data = (void *)RK_SPDIF_RK3066 },
{ .compatible = "rockchip,rk3188-spdif", { .compatible = "rockchip,rk3188-spdif",
.data = (void *) RK_SPDIF_RK3188 }, .data = (void *)RK_SPDIF_RK3188 },
{ .compatible = "rockchip,rk3288-spdif", { .compatible = "rockchip,rk3288-spdif",
.data = (void *) RK_SPDIF_RK3288 }, .data = (void *)RK_SPDIF_RK3288 },
{ .compatible = "rockchip,rk3366-spdif",
.data = (void *)RK_SPDIF_RK3366 },
{ .compatible = "rockchip,rk3368-spdif",
.data = (void *)RK_SPDIF_RK3366 },
{ .compatible = "rockchip,rk3399-spdif",
.data = (void *)RK_SPDIF_RK3366 },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, rk_spdif_match); MODULE_DEVICE_TABLE(of, rk_spdif_match);
static int rk_spdif_runtime_suspend(struct device *dev) static int __maybe_unused rk_spdif_runtime_suspend(struct device *dev)
{ {
struct rk_spdif_dev *spdif = dev_get_drvdata(dev); struct rk_spdif_dev *spdif = dev_get_drvdata(dev);
...@@ -64,7 +71,7 @@ static int rk_spdif_runtime_suspend(struct device *dev) ...@@ -64,7 +71,7 @@ static int rk_spdif_runtime_suspend(struct device *dev)
return 0; return 0;
} }
static int rk_spdif_runtime_resume(struct device *dev) static int __maybe_unused rk_spdif_runtime_resume(struct device *dev)
{ {
struct rk_spdif_dev *spdif = dev_get_drvdata(dev); struct rk_spdif_dev *spdif = dev_get_drvdata(dev);
int ret; int ret;
......
...@@ -90,6 +90,108 @@ static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io) ...@@ -90,6 +90,108 @@ static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io)
return (0x6 + ws) << 8; return (0x6 + ws) << 8;
} }
static void __rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv,
struct rsnd_dai_stream *io,
unsigned int target_rate,
unsigned int *target_val,
unsigned int *target_en)
{
struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
struct device *dev = rsnd_priv_to_dev(priv);
int idx, sel, div, step;
unsigned int val, en;
unsigned int min, diff;
unsigned int sel_rate[] = {
clk_get_rate(adg->clk[CLKA]), /* 0000: CLKA */
clk_get_rate(adg->clk[CLKB]), /* 0001: CLKB */
clk_get_rate(adg->clk[CLKC]), /* 0010: CLKC */
adg->rbga_rate_for_441khz, /* 0011: RBGA */
adg->rbgb_rate_for_48khz, /* 0100: RBGB */
};
min = ~0;
val = 0;
en = 0;
for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) {
idx = 0;
step = 2;
if (!sel_rate[sel])
continue;
for (div = 2; div <= 98304; div += step) {
diff = abs(target_rate - sel_rate[sel] / div);
if (min > diff) {
val = (sel << 8) | idx;
min = diff;
en = 1 << (sel + 1); /* fixme */
}
/*
* step of 0_0000 / 0_0001 / 0_1101
* are out of order
*/
if ((idx > 2) && (idx % 2))
step *= 2;
if (idx == 0x1c) {
div += step;
step *= 2;
}
idx++;
}
}
if (min == ~0) {
dev_err(dev, "no Input clock\n");
return;
}
*target_val = val;
if (target_en)
*target_en = en;
}
static void rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv,
struct rsnd_dai_stream *io,
unsigned int in_rate,
unsigned int out_rate,
u32 *in, u32 *out, u32 *en)
{
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
unsigned int target_rate;
u32 *target_val;
u32 _in;
u32 _out;
u32 _en;
/* default = SSI WS */
_in =
_out = rsnd_adg_ssi_ws_timing_gen2(io);
target_rate = 0;
target_val = NULL;
_en = 0;
if (runtime->rate != in_rate) {
target_rate = out_rate;
target_val = &_out;
} else if (runtime->rate != out_rate) {
target_rate = in_rate;
target_val = &_in;
}
if (target_rate)
__rsnd_adg_get_timesel_ratio(priv, io,
target_rate,
target_val, &_en);
if (in)
*in = _in;
if (out)
*out = _out;
if (en)
*en = _en;
}
int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod, int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod,
struct rsnd_dai_stream *io) struct rsnd_dai_stream *io)
{ {
...@@ -100,7 +202,10 @@ int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod, ...@@ -100,7 +202,10 @@ int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod,
int shift = (id % 2) ? 16 : 0; int shift = (id % 2) ? 16 : 0;
u32 mask, val; u32 mask, val;
val = rsnd_adg_ssi_ws_timing_gen2(io); rsnd_adg_get_timesel_ratio(priv, io,
rsnd_src_get_in_rate(priv, io),
rsnd_src_get_out_rate(priv, io),
NULL, &val, NULL);
val = val << shift; val = val << shift;
mask = 0xffff << shift; mask = 0xffff << shift;
...@@ -110,25 +215,24 @@ int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod, ...@@ -110,25 +215,24 @@ int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod,
return 0; return 0;
} }
static int rsnd_adg_set_src_timsel_gen2(struct rsnd_mod *src_mod, int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod,
struct rsnd_dai_stream *io, struct rsnd_dai_stream *io,
u32 timsel) unsigned int in_rate,
unsigned int out_rate)
{ {
struct rsnd_priv *priv = rsnd_mod_to_priv(src_mod); struct rsnd_priv *priv = rsnd_mod_to_priv(src_mod);
struct rsnd_adg *adg = rsnd_priv_to_adg(priv); struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
struct rsnd_mod *adg_mod = rsnd_mod_get(adg); struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
int is_play = rsnd_io_is_play(io); u32 in, out;
u32 mask, en;
int id = rsnd_mod_id(src_mod); int id = rsnd_mod_id(src_mod);
int shift = (id % 2) ? 16 : 0; int shift = (id % 2) ? 16 : 0;
u32 mask, ws;
u32 in, out;
rsnd_mod_confirm_src(src_mod); rsnd_mod_confirm_src(src_mod);
ws = rsnd_adg_ssi_ws_timing_gen2(io); rsnd_adg_get_timesel_ratio(priv, io,
in_rate, out_rate,
in = (is_play) ? timsel : ws; &in, &out, &en);
out = (is_play) ? ws : timsel;
in = in << shift; in = in << shift;
out = out << shift; out = out << shift;
...@@ -157,91 +261,12 @@ static int rsnd_adg_set_src_timsel_gen2(struct rsnd_mod *src_mod, ...@@ -157,91 +261,12 @@ static int rsnd_adg_set_src_timsel_gen2(struct rsnd_mod *src_mod,
break; break;
} }
return 0; if (en)
} rsnd_mod_bset(adg_mod, DIV_EN, en, en);
int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *src_mod,
struct rsnd_dai_stream *io,
unsigned int src_rate,
unsigned int dst_rate)
{
struct rsnd_priv *priv = rsnd_mod_to_priv(src_mod);
struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
struct device *dev = rsnd_priv_to_dev(priv);
int idx, sel, div, step, ret;
u32 val, en;
unsigned int min, diff;
unsigned int sel_rate [] = {
clk_get_rate(adg->clk[CLKA]), /* 0000: CLKA */
clk_get_rate(adg->clk[CLKB]), /* 0001: CLKB */
clk_get_rate(adg->clk[CLKC]), /* 0010: CLKC */
adg->rbga_rate_for_441khz, /* 0011: RBGA */
adg->rbgb_rate_for_48khz, /* 0100: RBGB */
};
rsnd_mod_confirm_src(src_mod);
min = ~0;
val = 0;
en = 0;
for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) {
idx = 0;
step = 2;
if (!sel_rate[sel])
continue;
for (div = 2; div <= 98304; div += step) {
diff = abs(src_rate - sel_rate[sel] / div);
if (min > diff) {
val = (sel << 8) | idx;
min = diff;
en = 1 << (sel + 1); /* fixme */
}
/*
* step of 0_0000 / 0_0001 / 0_1101
* are out of order
*/
if ((idx > 2) && (idx % 2))
step *= 2;
if (idx == 0x1c) {
div += step;
step *= 2;
}
idx++;
}
}
if (min == ~0) {
dev_err(dev, "no Input clock\n");
return -EIO;
}
ret = rsnd_adg_set_src_timsel_gen2(src_mod, io, val);
if (ret < 0) {
dev_err(dev, "timsel error\n");
return ret;
}
rsnd_mod_bset(adg_mod, DIV_EN, en, en);
dev_dbg(dev, "convert rate %d <-> %d\n", src_rate, dst_rate);
return 0; return 0;
} }
int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *src_mod,
struct rsnd_dai_stream *io)
{
u32 val = rsnd_adg_ssi_ws_timing_gen2(io);
rsnd_mod_confirm_src(src_mod);
return rsnd_adg_set_src_timsel_gen2(src_mod, io, val);
}
static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val) static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
{ {
struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
...@@ -518,13 +543,8 @@ int rsnd_adg_probe(struct rsnd_priv *priv) ...@@ -518,13 +543,8 @@ int rsnd_adg_probe(struct rsnd_priv *priv)
return -ENOMEM; return -ENOMEM;
} }
/* rsnd_mod_init(priv, &adg->mod, &adg_ops,
* ADG is special module. NULL, NULL, 0, 0);
* Use ADG mod without rsnd_mod_init() to make debug easy
* for rsnd_write/rsnd_read
*/
adg->mod.ops = &adg_ops;
adg->mod.priv = priv;
rsnd_adg_get_clkin(priv, adg); rsnd_adg_get_clkin(priv, adg);
rsnd_adg_get_clkout(priv, adg); rsnd_adg_get_clkout(priv, adg);
......
...@@ -29,7 +29,6 @@ static int rsnd_cmd_init(struct rsnd_mod *mod, ...@@ -29,7 +29,6 @@ static int rsnd_cmd_init(struct rsnd_mod *mod,
{ {
struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
struct rsnd_mod *mix = rsnd_io_to_mod_mix(io); struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
struct rsnd_mod *src = rsnd_io_to_mod_src(io);
struct device *dev = rsnd_priv_to_dev(priv); struct device *dev = rsnd_priv_to_dev(priv);
u32 data; u32 data;
...@@ -38,6 +37,8 @@ static int rsnd_cmd_init(struct rsnd_mod *mod, ...@@ -38,6 +37,8 @@ static int rsnd_cmd_init(struct rsnd_mod *mod,
if (mix) { if (mix) {
struct rsnd_dai *rdai; struct rsnd_dai *rdai;
struct rsnd_mod *src;
struct rsnd_dai_stream *tio;
int i; int i;
u32 path[] = { u32 path[] = {
[0] = 0, [0] = 0,
...@@ -55,16 +56,20 @@ static int rsnd_cmd_init(struct rsnd_mod *mod, ...@@ -55,16 +56,20 @@ static int rsnd_cmd_init(struct rsnd_mod *mod,
*/ */
data = 0; data = 0;
for_each_rsnd_dai(rdai, priv, i) { for_each_rsnd_dai(rdai, priv, i) {
io = &rdai->playback; tio = &rdai->playback;
if (mix == rsnd_io_to_mod_mix(io)) src = rsnd_io_to_mod_src(tio);
if (mix == rsnd_io_to_mod_mix(tio))
data |= path[rsnd_mod_id(src)]; data |= path[rsnd_mod_id(src)];
io = &rdai->capture; tio = &rdai->capture;
if (mix == rsnd_io_to_mod_mix(io)) src = rsnd_io_to_mod_src(tio);
if (mix == rsnd_io_to_mod_mix(tio))
data |= path[rsnd_mod_id(src)]; data |= path[rsnd_mod_id(src)];
} }
} else { } else {
struct rsnd_mod *src = rsnd_io_to_mod_src(io);
u32 path[] = { u32 path[] = {
[0] = 0x30000, [0] = 0x30000,
[1] = 0x30001, [1] = 0x30001,
...@@ -152,7 +157,8 @@ int rsnd_cmd_probe(struct rsnd_priv *priv) ...@@ -152,7 +157,8 @@ int rsnd_cmd_probe(struct rsnd_priv *priv)
for_each_rsnd_cmd(cmd, priv, i) { for_each_rsnd_cmd(cmd, priv, i) {
ret = rsnd_mod_init(priv, rsnd_mod_get(cmd), ret = rsnd_mod_init(priv, rsnd_mod_get(cmd),
&rsnd_cmd_ops, NULL, RSND_MOD_CMD, i); &rsnd_cmd_ops, NULL,
rsnd_mod_get_status, RSND_MOD_CMD, i);
if (ret) if (ret)
return ret; return ret;
} }
......
...@@ -138,12 +138,22 @@ struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io, ...@@ -138,12 +138,22 @@ struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
return mod->ops->dma_req(io, mod); return mod->ops->dma_req(io, mod);
} }
u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io,
struct rsnd_mod *mod,
enum rsnd_mod_type type)
{
return &mod->status;
}
int rsnd_mod_init(struct rsnd_priv *priv, int rsnd_mod_init(struct rsnd_priv *priv,
struct rsnd_mod *mod, struct rsnd_mod *mod,
struct rsnd_mod_ops *ops, struct rsnd_mod_ops *ops,
struct clk *clk, struct clk *clk,
enum rsnd_mod_type type, u32* (*get_status)(struct rsnd_dai_stream *io,
int id) struct rsnd_mod *mod,
enum rsnd_mod_type type),
enum rsnd_mod_type type,
int id)
{ {
int ret = clk_prepare(clk); int ret = clk_prepare(clk);
...@@ -155,6 +165,7 @@ int rsnd_mod_init(struct rsnd_priv *priv, ...@@ -155,6 +165,7 @@ int rsnd_mod_init(struct rsnd_priv *priv,
mod->type = type; mod->type = type;
mod->clk = clk; mod->clk = clk;
mod->priv = priv; mod->priv = priv;
mod->get_status = get_status;
return ret; return ret;
} }
...@@ -163,6 +174,7 @@ void rsnd_mod_quit(struct rsnd_mod *mod) ...@@ -163,6 +174,7 @@ void rsnd_mod_quit(struct rsnd_mod *mod)
{ {
if (mod->clk) if (mod->clk)
clk_unprepare(mod->clk); clk_unprepare(mod->clk);
mod->clk = NULL;
} }
void rsnd_mod_interrupt(struct rsnd_mod *mod, void rsnd_mod_interrupt(struct rsnd_mod *mod,
...@@ -212,13 +224,36 @@ int rsnd_get_slot_num(struct rsnd_dai_stream *io) ...@@ -212,13 +224,36 @@ int rsnd_get_slot_num(struct rsnd_dai_stream *io)
return rdai->slots_num; return rdai->slots_num;
} }
int rsnd_get_slot_width(struct rsnd_dai_stream *io) int rsnd_runtime_channel_original(struct rsnd_dai_stream *io)
{ {
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
int chan = runtime->channels;
/* Multi channel Mode */ return runtime->channels;
if (rsnd_ssi_multi_slaves(io)) }
int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io)
{
int chan = rsnd_runtime_channel_original(io);
struct rsnd_mod *ctu_mod = rsnd_io_to_mod_ctu(io);
if (ctu_mod) {
u32 converted_chan = rsnd_ctu_converted_channel(ctu_mod);
if (converted_chan)
return converted_chan;
}
return chan;
}
int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io)
{
int chan = rsnd_io_is_play(io) ?
rsnd_runtime_channel_after_ctu(io) :
rsnd_runtime_channel_original(io);
/* Use Multi SSI */
if (rsnd_runtime_is_ssi_multi(io))
chan /= rsnd_get_slot_num(io); chan /= rsnd_get_slot_num(io);
/* TDM Extend Mode needs 8ch */ /* TDM Extend Mode needs 8ch */
...@@ -228,6 +263,21 @@ int rsnd_get_slot_width(struct rsnd_dai_stream *io) ...@@ -228,6 +263,21 @@ int rsnd_get_slot_width(struct rsnd_dai_stream *io)
return chan; return chan;
} }
int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io)
{
int slots = rsnd_get_slot_num(io);
int chan = rsnd_io_is_play(io) ?
rsnd_runtime_channel_after_ctu(io) :
rsnd_runtime_channel_original(io);
return (chan >= 6) && (slots > 1);
}
int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io)
{
return rsnd_runtime_channel_for_ssi(io) >= 6;
}
/* /*
* ADINR function * ADINR function
*/ */
...@@ -249,29 +299,6 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io) ...@@ -249,29 +299,6 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
return 0; return 0;
} }
u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
{
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
struct device *dev = rsnd_priv_to_dev(priv);
u32 chan = runtime->channels;
switch (chan) {
case 1:
case 2:
case 4:
case 6:
case 8:
break;
default:
dev_warn(dev, "not supported channel\n");
chan = 0;
break;
}
return chan;
}
/* /*
* DALIGN function * DALIGN function
*/ */
...@@ -324,31 +351,73 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) ...@@ -324,31 +351,73 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \ struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \
struct rsnd_mod *mod = (io)->mod[idx]; \ struct rsnd_mod *mod = (io)->mod[idx]; \
struct device *dev = rsnd_priv_to_dev(priv); \ struct device *dev = rsnd_priv_to_dev(priv); \
u32 *status = (io)->mod_status + idx; \ u32 *status = mod->get_status(io, mod, idx); \
u32 mask = 0xF << __rsnd_mod_shift_##func; \ u32 mask = 0xF << __rsnd_mod_shift_##func; \
u8 val = (*status >> __rsnd_mod_shift_##func) & 0xF; \ u8 val = (*status >> __rsnd_mod_shift_##func) & 0xF; \
u8 add = ((val + __rsnd_mod_add_##func) & 0xF); \ u8 add = ((val + __rsnd_mod_add_##func) & 0xF); \
int ret = 0; \ int ret = 0; \
int call = (val == __rsnd_mod_call_##func) && (mod)->ops->func; \ int call = (val == __rsnd_mod_call_##func) && (mod)->ops->func; \
*status = (*status & ~mask) + \ if (add == 0xF) \
(add << __rsnd_mod_shift_##func); \ call = 0; \
else \
*status = (*status & ~mask) + \
(add << __rsnd_mod_shift_##func); \
dev_dbg(dev, "%s[%d]\t0x%08x %s\n", \ dev_dbg(dev, "%s[%d]\t0x%08x %s\n", \
rsnd_mod_name(mod), rsnd_mod_id(mod), \ rsnd_mod_name(mod), rsnd_mod_id(mod), \
*status, call ? #func : ""); \ *status, call ? #func : ""); \
if (call) \ if (call) \
ret = (mod)->ops->func(mod, io, param); \ ret = (mod)->ops->func(mod, io, param); \
if (ret) \
dev_dbg(dev, "%s[%d] : rsnd_mod_call error %d\n", \
rsnd_mod_name(mod), rsnd_mod_id(mod), ret); \
ret; \ ret; \
}) })
static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = {
{
/* CAPTURE */
RSND_MOD_AUDMAPP,
RSND_MOD_AUDMA,
RSND_MOD_DVC,
RSND_MOD_MIX,
RSND_MOD_CTU,
RSND_MOD_CMD,
RSND_MOD_SRC,
RSND_MOD_SSIU,
RSND_MOD_SSIM3,
RSND_MOD_SSIM2,
RSND_MOD_SSIM1,
RSND_MOD_SSIP,
RSND_MOD_SSI,
}, {
/* PLAYBACK */
RSND_MOD_AUDMAPP,
RSND_MOD_AUDMA,
RSND_MOD_SSIM3,
RSND_MOD_SSIM2,
RSND_MOD_SSIM1,
RSND_MOD_SSIP,
RSND_MOD_SSI,
RSND_MOD_SSIU,
RSND_MOD_DVC,
RSND_MOD_MIX,
RSND_MOD_CTU,
RSND_MOD_CMD,
RSND_MOD_SRC,
},
};
#define rsnd_dai_call(fn, io, param...) \ #define rsnd_dai_call(fn, io, param...) \
({ \ ({ \
struct rsnd_mod *mod; \ struct rsnd_mod *mod; \
int type, is_play = rsnd_io_is_play(io); \
int ret = 0, i; \ int ret = 0, i; \
for (i = 0; i < RSND_MOD_MAX; i++) { \ for (i = 0; i < RSND_MOD_MAX; i++) { \
mod = (io)->mod[i]; \ type = rsnd_mod_sequence[is_play][i]; \
mod = (io)->mod[type]; \
if (!mod) \ if (!mod) \
continue; \ continue; \
ret |= rsnd_mod_call(i, io, fn, param); \ ret |= rsnd_mod_call(type, io, fn, param); \
} \ } \
ret; \ ret; \
}) })
...@@ -363,6 +432,9 @@ int rsnd_dai_connect(struct rsnd_mod *mod, ...@@ -363,6 +432,9 @@ int rsnd_dai_connect(struct rsnd_mod *mod,
if (!mod) if (!mod)
return -EIO; return -EIO;
if (io->mod[type] == mod)
return 0;
if (io->mod[type]) if (io->mod[type])
return -EINVAL; return -EINVAL;
...@@ -511,9 +583,16 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, ...@@ -511,9 +583,16 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
ret = rsnd_dai_call(start, io, priv); ret = rsnd_dai_call(start, io, priv);
if (ret < 0) if (ret < 0)
goto dai_trigger_end; goto dai_trigger_end;
ret = rsnd_dai_call(irq, io, priv, 1);
if (ret < 0)
goto dai_trigger_end;
break; break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
ret = rsnd_dai_call(stop, io, priv); ret = rsnd_dai_call(irq, io, priv, 0);
ret |= rsnd_dai_call(stop, io, priv);
ret |= rsnd_dai_call(quit, io, priv); ret |= rsnd_dai_call(quit, io, priv);
...@@ -863,7 +942,7 @@ static int rsnd_kctrl_put(struct snd_kcontrol *kctrl, ...@@ -863,7 +942,7 @@ static int rsnd_kctrl_put(struct snd_kcontrol *kctrl,
} }
} }
if (change) if (change && cfg->update)
cfg->update(cfg->io, mod); cfg->update(cfg->io, mod);
return change; return change;
...@@ -923,7 +1002,7 @@ int rsnd_kctrl_new_m(struct rsnd_mod *mod, ...@@ -923,7 +1002,7 @@ int rsnd_kctrl_new_m(struct rsnd_mod *mod,
int ch_size, int ch_size,
u32 max) u32 max)
{ {
if (ch_size > RSND_DVC_CHANNELS) if (ch_size > RSND_MAX_CHANNELS)
return -EINVAL; return -EINVAL;
_cfg->cfg.max = max; _cfg->cfg.max = max;
...@@ -1055,7 +1134,6 @@ static int rsnd_probe(struct platform_device *pdev) ...@@ -1055,7 +1134,6 @@ static int rsnd_probe(struct platform_device *pdev)
struct rsnd_priv *priv; struct rsnd_priv *priv;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct rsnd_dai *rdai; struct rsnd_dai *rdai;
const struct of_device_id *of_id = of_match_device(rsnd_of_match, dev);
int (*probe_func[])(struct rsnd_priv *priv) = { int (*probe_func[])(struct rsnd_priv *priv) = {
rsnd_gen_probe, rsnd_gen_probe,
rsnd_dma_probe, rsnd_dma_probe,
...@@ -1081,7 +1159,7 @@ static int rsnd_probe(struct platform_device *pdev) ...@@ -1081,7 +1159,7 @@ static int rsnd_probe(struct platform_device *pdev)
} }
priv->pdev = pdev; priv->pdev = pdev;
priv->flags = (unsigned long)of_id->data; priv->flags = (unsigned long)of_device_get_match_data(dev);
spin_lock_init(&priv->lock); spin_lock_init(&priv->lock);
/* /*
......
...@@ -12,8 +12,75 @@ ...@@ -12,8 +12,75 @@
#define CTU_NAME_SIZE 16 #define CTU_NAME_SIZE 16
#define CTU_NAME "ctu" #define CTU_NAME "ctu"
/*
* User needs to setup CTU by amixer, and its settings are
* based on below registers
*
* CTUn_CPMDR : amixser set "CTU Pass"
* CTUn_SV0xR : amixser set "CTU SV0"
* CTUn_SV1xR : amixser set "CTU SV1"
* CTUn_SV2xR : amixser set "CTU SV2"
* CTUn_SV3xR : amixser set "CTU SV3"
*
* [CTU Pass]
* 0000: default
* 0001: Connect input data of channel 0
* 0010: Connect input data of channel 1
* 0011: Connect input data of channel 2
* 0100: Connect input data of channel 3
* 0101: Connect input data of channel 4
* 0110: Connect input data of channel 5
* 0111: Connect input data of channel 6
* 1000: Connect input data of channel 7
* 1001: Connect calculated data by scale values of matrix row 0
* 1010: Connect calculated data by scale values of matrix row 1
* 1011: Connect calculated data by scale values of matrix row 2
* 1100: Connect calculated data by scale values of matrix row 3
*
* [CTU SVx]
* [Output0] = [SV00, SV01, SV02, SV03, SV04, SV05, SV06, SV07]
* [Output1] = [SV10, SV11, SV12, SV13, SV14, SV15, SV16, SV17]
* [Output2] = [SV20, SV21, SV22, SV23, SV24, SV25, SV26, SV27]
* [Output3] = [SV30, SV31, SV32, SV33, SV34, SV35, SV36, SV37]
* [Output4] = [ 0, 0, 0, 0, 0, 0, 0, 0 ]
* [Output5] = [ 0, 0, 0, 0, 0, 0, 0, 0 ]
* [Output6] = [ 0, 0, 0, 0, 0, 0, 0, 0 ]
* [Output7] = [ 0, 0, 0, 0, 0, 0, 0, 0 ]
*
* [SVxx]
* Plus Minus
* value time dB value time dB
* -----------------------------------------------------------------------
* H'7F_FFFF 2 6 H'80_0000 2 6
* ...
* H'40_0000 1 0 H'C0_0000 1 0
* ...
* H'00_0001 2.38 x 10^-7 -132
* H'00_0000 0 Mute H'FF_FFFF 2.38 x 10^-7 -132
*
*
* Ex) Input ch -> Output ch
* 1ch -> 0ch
* 0ch -> 1ch
*
* amixer set "CTU Reset" on
* amixer set "CTU Pass" 9,10
* amixer set "CTU SV0" 0,4194304
* amixer set "CTU SV1" 4194304,0
* or
* amixer set "CTU Reset" on
* amixer set "CTU Pass" 2,1
*/
struct rsnd_ctu { struct rsnd_ctu {
struct rsnd_mod mod; struct rsnd_mod mod;
struct rsnd_kctrl_cfg_m pass;
struct rsnd_kctrl_cfg_m sv0;
struct rsnd_kctrl_cfg_m sv1;
struct rsnd_kctrl_cfg_m sv2;
struct rsnd_kctrl_cfg_m sv3;
struct rsnd_kctrl_cfg_s reset;
int channels;
}; };
#define rsnd_ctu_nr(priv) ((priv)->ctu_nr) #define rsnd_ctu_nr(priv) ((priv)->ctu_nr)
...@@ -23,12 +90,28 @@ struct rsnd_ctu { ...@@ -23,12 +90,28 @@ struct rsnd_ctu {
((pos) = (struct rsnd_ctu *)(priv)->ctu + i); \ ((pos) = (struct rsnd_ctu *)(priv)->ctu + i); \
i++) i++)
#define rsnd_mod_to_ctu(_mod) \
container_of((_mod), struct rsnd_ctu, mod)
#define rsnd_ctu_get(priv, id) ((struct rsnd_ctu *)(priv->ctu) + id) #define rsnd_ctu_get(priv, id) ((struct rsnd_ctu *)(priv->ctu) + id)
#define rsnd_ctu_initialize_lock(mod) __rsnd_ctu_initialize_lock(mod, 1)
#define rsnd_ctu_initialize_unlock(mod) __rsnd_ctu_initialize_lock(mod, 0) static void rsnd_ctu_activation(struct rsnd_mod *mod)
static void __rsnd_ctu_initialize_lock(struct rsnd_mod *mod, u32 enable) {
rsnd_mod_write(mod, CTU_SWRSR, 0);
rsnd_mod_write(mod, CTU_SWRSR, 1);
}
static void rsnd_ctu_halt(struct rsnd_mod *mod)
{
rsnd_mod_write(mod, CTU_CTUIR, 1);
rsnd_mod_write(mod, CTU_SWRSR, 0);
}
int rsnd_ctu_converted_channel(struct rsnd_mod *mod)
{ {
rsnd_mod_write(mod, CTU_CTUIR, enable); struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
return ctu->channels;
} }
static int rsnd_ctu_probe_(struct rsnd_mod *mod, static int rsnd_ctu_probe_(struct rsnd_mod *mod,
...@@ -38,17 +121,103 @@ static int rsnd_ctu_probe_(struct rsnd_mod *mod, ...@@ -38,17 +121,103 @@ static int rsnd_ctu_probe_(struct rsnd_mod *mod,
return rsnd_cmd_attach(io, rsnd_mod_id(mod) / 4); return rsnd_cmd_attach(io, rsnd_mod_id(mod) / 4);
} }
static void rsnd_ctu_value_init(struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
u32 cpmdr = 0;
u32 scmdr = 0;
int i;
for (i = 0; i < RSND_MAX_CHANNELS; i++) {
u32 val = ctu->pass.val[i];
cpmdr |= val << (28 - (i * 4));
if ((val > 0x8) && (scmdr < (val - 0x8)))
scmdr = val - 0x8;
}
rsnd_mod_write(mod, CTU_CTUIR, 1);
rsnd_mod_write(mod, CTU_ADINR, rsnd_runtime_channel_original(io));
rsnd_mod_write(mod, CTU_CPMDR, cpmdr);
rsnd_mod_write(mod, CTU_SCMDR, scmdr);
if (scmdr > 0) {
rsnd_mod_write(mod, CTU_SV00R, ctu->sv0.val[0]);
rsnd_mod_write(mod, CTU_SV01R, ctu->sv0.val[1]);
rsnd_mod_write(mod, CTU_SV02R, ctu->sv0.val[2]);
rsnd_mod_write(mod, CTU_SV03R, ctu->sv0.val[3]);
rsnd_mod_write(mod, CTU_SV04R, ctu->sv0.val[4]);
rsnd_mod_write(mod, CTU_SV05R, ctu->sv0.val[5]);
rsnd_mod_write(mod, CTU_SV06R, ctu->sv0.val[6]);
rsnd_mod_write(mod, CTU_SV07R, ctu->sv0.val[7]);
}
if (scmdr > 1) {
rsnd_mod_write(mod, CTU_SV10R, ctu->sv1.val[0]);
rsnd_mod_write(mod, CTU_SV11R, ctu->sv1.val[1]);
rsnd_mod_write(mod, CTU_SV12R, ctu->sv1.val[2]);
rsnd_mod_write(mod, CTU_SV13R, ctu->sv1.val[3]);
rsnd_mod_write(mod, CTU_SV14R, ctu->sv1.val[4]);
rsnd_mod_write(mod, CTU_SV15R, ctu->sv1.val[5]);
rsnd_mod_write(mod, CTU_SV16R, ctu->sv1.val[6]);
rsnd_mod_write(mod, CTU_SV17R, ctu->sv1.val[7]);
}
if (scmdr > 2) {
rsnd_mod_write(mod, CTU_SV20R, ctu->sv2.val[0]);
rsnd_mod_write(mod, CTU_SV21R, ctu->sv2.val[1]);
rsnd_mod_write(mod, CTU_SV22R, ctu->sv2.val[2]);
rsnd_mod_write(mod, CTU_SV23R, ctu->sv2.val[3]);
rsnd_mod_write(mod, CTU_SV24R, ctu->sv2.val[4]);
rsnd_mod_write(mod, CTU_SV25R, ctu->sv2.val[5]);
rsnd_mod_write(mod, CTU_SV26R, ctu->sv2.val[6]);
rsnd_mod_write(mod, CTU_SV27R, ctu->sv2.val[7]);
}
if (scmdr > 3) {
rsnd_mod_write(mod, CTU_SV30R, ctu->sv3.val[0]);
rsnd_mod_write(mod, CTU_SV31R, ctu->sv3.val[1]);
rsnd_mod_write(mod, CTU_SV32R, ctu->sv3.val[2]);
rsnd_mod_write(mod, CTU_SV33R, ctu->sv3.val[3]);
rsnd_mod_write(mod, CTU_SV34R, ctu->sv3.val[4]);
rsnd_mod_write(mod, CTU_SV35R, ctu->sv3.val[5]);
rsnd_mod_write(mod, CTU_SV36R, ctu->sv3.val[6]);
rsnd_mod_write(mod, CTU_SV37R, ctu->sv3.val[7]);
}
rsnd_mod_write(mod, CTU_CTUIR, 0);
}
static void rsnd_ctu_value_reset(struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
int i;
if (!ctu->reset.val)
return;
for (i = 0; i < RSND_MAX_CHANNELS; i++) {
ctu->pass.val[i] = 0;
ctu->sv0.val[i] = 0;
ctu->sv1.val[i] = 0;
ctu->sv2.val[i] = 0;
ctu->sv3.val[i] = 0;
}
ctu->reset.val = 0;
}
static int rsnd_ctu_init(struct rsnd_mod *mod, static int rsnd_ctu_init(struct rsnd_mod *mod,
struct rsnd_dai_stream *io, struct rsnd_dai_stream *io,
struct rsnd_priv *priv) struct rsnd_priv *priv)
{ {
rsnd_mod_power_on(mod); rsnd_mod_power_on(mod);
rsnd_ctu_initialize_lock(mod); rsnd_ctu_activation(mod);
rsnd_mod_write(mod, CTU_ADINR, rsnd_get_adinr_chan(mod, io));
rsnd_ctu_initialize_unlock(mod); rsnd_ctu_value_init(io, mod);
return 0; return 0;
} }
...@@ -57,16 +226,110 @@ static int rsnd_ctu_quit(struct rsnd_mod *mod, ...@@ -57,16 +226,110 @@ static int rsnd_ctu_quit(struct rsnd_mod *mod,
struct rsnd_dai_stream *io, struct rsnd_dai_stream *io,
struct rsnd_priv *priv) struct rsnd_priv *priv)
{ {
rsnd_ctu_halt(mod);
rsnd_mod_power_off(mod); rsnd_mod_power_off(mod);
return 0; return 0;
} }
static int rsnd_ctu_hw_params(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *fe_params)
{
struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
struct snd_soc_pcm_runtime *fe = substream->private_data;
/*
* CTU assumes that it is used under DPCM if user want to use
* channel transfer. Then, CTU should be FE.
* And then, this function will be called *after* BE settings.
* this means, each BE already has fixuped hw_params.
* see
* dpcm_fe_dai_hw_params()
* dpcm_be_dai_hw_params()
*/
ctu->channels = 0;
if (fe->dai_link->dynamic) {
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv);
struct snd_soc_dpcm *dpcm;
struct snd_pcm_hw_params *be_params;
int stream = substream->stream;
list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
be_params = &dpcm->hw_params;
if (params_channels(fe_params) != params_channels(be_params))
ctu->channels = params_channels(be_params);
}
dev_dbg(dev, "CTU convert channels %d\n", ctu->channels);
}
return 0;
}
static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct snd_soc_pcm_runtime *rtd)
{
struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
int ret;
/* CTU Pass */
ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU Pass",
NULL,
&ctu->pass, RSND_MAX_CHANNELS,
0xC);
/* ROW0 */
ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV0",
NULL,
&ctu->sv0, RSND_MAX_CHANNELS,
0x00FFFFFF);
if (ret < 0)
return ret;
/* ROW1 */
ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV1",
NULL,
&ctu->sv1, RSND_MAX_CHANNELS,
0x00FFFFFF);
if (ret < 0)
return ret;
/* ROW2 */
ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV2",
NULL,
&ctu->sv2, RSND_MAX_CHANNELS,
0x00FFFFFF);
if (ret < 0)
return ret;
/* ROW3 */
ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV3",
NULL,
&ctu->sv3, RSND_MAX_CHANNELS,
0x00FFFFFF);
if (ret < 0)
return ret;
/* Reset */
ret = rsnd_kctrl_new_s(mod, io, rtd, "CTU Reset",
rsnd_ctu_value_reset,
&ctu->reset, 1);
return ret;
}
static struct rsnd_mod_ops rsnd_ctu_ops = { static struct rsnd_mod_ops rsnd_ctu_ops = {
.name = CTU_NAME, .name = CTU_NAME,
.probe = rsnd_ctu_probe_, .probe = rsnd_ctu_probe_,
.init = rsnd_ctu_init, .init = rsnd_ctu_init,
.quit = rsnd_ctu_quit, .quit = rsnd_ctu_quit,
.hw_params = rsnd_ctu_hw_params,
.pcm_new = rsnd_ctu_pcm_new,
}; };
struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id) struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id)
...@@ -129,7 +392,7 @@ int rsnd_ctu_probe(struct rsnd_priv *priv) ...@@ -129,7 +392,7 @@ int rsnd_ctu_probe(struct rsnd_priv *priv)
} }
ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops, ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops,
clk, RSND_MOD_CTU, i); clk, rsnd_mod_get_status, RSND_MOD_CTU, i);
if (ret) if (ret)
goto rsnd_ctu_probe_done; goto rsnd_ctu_probe_done;
......
...@@ -622,15 +622,13 @@ static void rsnd_dma_of_path(struct rsnd_mod *this, ...@@ -622,15 +622,13 @@ static void rsnd_dma_of_path(struct rsnd_mod *this,
} }
} }
struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io, int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
struct rsnd_mod *mod, int id) struct rsnd_mod **dma_mod, int id)
{ {
struct rsnd_mod *dma_mod;
struct rsnd_mod *mod_from = NULL; struct rsnd_mod *mod_from = NULL;
struct rsnd_mod *mod_to = NULL; struct rsnd_mod *mod_to = NULL;
struct rsnd_priv *priv = rsnd_io_to_priv(io); struct rsnd_priv *priv = rsnd_io_to_priv(io);
struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
struct rsnd_dma *dma;
struct device *dev = rsnd_priv_to_dev(priv); struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_mod_ops *ops; struct rsnd_mod_ops *ops;
enum rsnd_mod_type type; enum rsnd_mod_type type;
...@@ -646,17 +644,10 @@ struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io, ...@@ -646,17 +644,10 @@ struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io,
* rsnd_rdai_continuance_probe() * rsnd_rdai_continuance_probe()
*/ */
if (!dmac) if (!dmac)
return ERR_PTR(-EAGAIN); return -EAGAIN;
dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
if (!dma)
return ERR_PTR(-ENOMEM);
rsnd_dma_of_path(mod, io, is_play, &mod_from, &mod_to); rsnd_dma_of_path(mod, io, is_play, &mod_from, &mod_to);
dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1);
dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0);
/* for Gen2 */ /* for Gen2 */
if (mod_from && mod_to) { if (mod_from && mod_to) {
ops = &rsnd_dmapp_ops; ops = &rsnd_dmapp_ops;
...@@ -678,27 +669,38 @@ struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io, ...@@ -678,27 +669,38 @@ struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io,
type = RSND_MOD_AUDMA; type = RSND_MOD_AUDMA;
} }
dma_mod = rsnd_mod_get(dma); if (!(*dma_mod)) {
struct rsnd_dma *dma;
ret = rsnd_mod_init(priv, dma_mod, dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
ops, NULL, type, dma_id); if (!dma)
if (ret < 0) return -ENOMEM;
return ERR_PTR(ret);
dev_dbg(dev, "%s[%d] %s[%d] -> %s[%d]\n", *dma_mod = rsnd_mod_get(dma);
rsnd_mod_name(dma_mod), rsnd_mod_id(dma_mod),
rsnd_mod_name(mod_from), rsnd_mod_id(mod_from),
rsnd_mod_name(mod_to), rsnd_mod_id(mod_to));
ret = attach(io, dma, id, mod_from, mod_to); dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1);
if (ret < 0) dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0);
return ERR_PTR(ret);
ret = rsnd_mod_init(priv, *dma_mod, ops, NULL,
rsnd_mod_get_status, type, dma_id);
if (ret < 0)
return ret;
ret = rsnd_dai_connect(dma_mod, io, type); dev_dbg(dev, "%s[%d] %s[%d] -> %s[%d]\n",
rsnd_mod_name(*dma_mod), rsnd_mod_id(*dma_mod),
rsnd_mod_name(mod_from), rsnd_mod_id(mod_from),
rsnd_mod_name(mod_to), rsnd_mod_id(mod_to));
ret = attach(io, dma, id, mod_from, mod_to);
if (ret < 0)
return ret;
}
ret = rsnd_dai_connect(*dma_mod, io, type);
if (ret < 0) if (ret < 0)
return ERR_PTR(ret); return ret;
return rsnd_mod_get(dma); return 0;
} }
int rsnd_dma_probe(struct rsnd_priv *priv) int rsnd_dma_probe(struct rsnd_priv *priv)
......
...@@ -8,6 +8,29 @@ ...@@ -8,6 +8,29 @@
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
/*
* Playback Volume
* amixer set "DVC Out" 100%
*
* Capture Volume
* amixer set "DVC In" 100%
*
* Playback Mute
* amixer set "DVC Out Mute" on
*
* Capture Mute
* amixer set "DVC In Mute" on
*
* Volume Ramp
* amixer set "DVC Out Ramp Up Rate" "0.125 dB/64 steps"
* amixer set "DVC Out Ramp Down Rate" "0.125 dB/512 steps"
* amixer set "DVC Out Ramp" on
* aplay xxx.wav &
* amixer set "DVC Out" 80% // Volume Down
* amixer set "DVC Out" 100% // Volume Up
*/
#include "rsnd.h" #include "rsnd.h"
#define RSND_DVC_NAME_SIZE 16 #define RSND_DVC_NAME_SIZE 16
...@@ -83,15 +106,15 @@ static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io, ...@@ -83,15 +106,15 @@ static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io,
struct rsnd_mod *mod) struct rsnd_mod *mod)
{ {
struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
u32 val[RSND_DVC_CHANNELS]; u32 val[RSND_MAX_CHANNELS];
int i; int i;
/* Enable Ramp */ /* Enable Ramp */
if (dvc->ren.val) if (dvc->ren.val)
for (i = 0; i < RSND_DVC_CHANNELS; i++) for (i = 0; i < RSND_MAX_CHANNELS; i++)
val[i] = dvc->volume.cfg.max; val[i] = dvc->volume.cfg.max;
else else
for (i = 0; i < RSND_DVC_CHANNELS; i++) for (i = 0; i < RSND_MAX_CHANNELS; i++)
val[i] = dvc->volume.val[i]; val[i] = dvc->volume.val[i];
/* Enable Digital Volume */ /* Enable Digital Volume */
...@@ -116,7 +139,7 @@ static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io, ...@@ -116,7 +139,7 @@ static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io,
u32 vrdbr = 0; u32 vrdbr = 0;
adinr = rsnd_get_adinr_bit(mod, io) | adinr = rsnd_get_adinr_bit(mod, io) |
rsnd_get_adinr_chan(mod, io); rsnd_runtime_channel_after_ctu(io);
/* Enable Digital Volume, Zero Cross Mute Mode */ /* Enable Digital Volume, Zero Cross Mute Mode */
dvucr |= 0x101; dvucr |= 0x101;
...@@ -373,7 +396,7 @@ int rsnd_dvc_probe(struct rsnd_priv *priv) ...@@ -373,7 +396,7 @@ int rsnd_dvc_probe(struct rsnd_priv *priv)
} }
ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops, ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops,
clk, RSND_MOD_DVC, i); clk, rsnd_mod_get_status, RSND_MOD_DVC, i);
if (ret) if (ret)
goto rsnd_dvc_probe_done; goto rsnd_dvc_probe_done;
......
...@@ -101,23 +101,6 @@ void rsnd_write(struct rsnd_priv *priv, ...@@ -101,23 +101,6 @@ void rsnd_write(struct rsnd_priv *priv,
struct device *dev = rsnd_priv_to_dev(priv); struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_gen *gen = rsnd_priv_to_gen(priv); struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
if (!rsnd_is_accessible_reg(priv, gen, reg))
return;
regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data);
dev_dbg(dev, "w %s[%d] - %-18s (%4d) : %08x\n",
rsnd_mod_name(mod), rsnd_mod_id(mod),
rsnd_reg_name(gen, reg), reg, data);
}
void rsnd_force_write(struct rsnd_priv *priv,
struct rsnd_mod *mod,
enum rsnd_reg reg, u32 data)
{
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
if (!rsnd_is_accessible_reg(priv, gen, reg)) if (!rsnd_is_accessible_reg(priv, gen, reg))
return; return;
...@@ -137,8 +120,8 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, ...@@ -137,8 +120,8 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
if (!rsnd_is_accessible_reg(priv, gen, reg)) if (!rsnd_is_accessible_reg(priv, gen, reg))
return; return;
regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod), regmap_fields_force_update_bits(gen->regs[reg],
mask, data); rsnd_mod_id(mod), mask, data);
dev_dbg(dev, "b %s[%d] - %-18s (%4d) : %08x/%08x\n", dev_dbg(dev, "b %s[%d] - %-18s (%4d) : %08x/%08x\n",
rsnd_mod_name(mod), rsnd_mod_id(mod), rsnd_mod_name(mod), rsnd_mod_id(mod),
...@@ -260,8 +243,43 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) ...@@ -260,8 +243,43 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv)
RSND_GEN_M_REG(SRC_SRCCR, 0x224, 0x40), RSND_GEN_M_REG(SRC_SRCCR, 0x224, 0x40),
RSND_GEN_M_REG(SRC_BSDSR, 0x22c, 0x40), RSND_GEN_M_REG(SRC_BSDSR, 0x22c, 0x40),
RSND_GEN_M_REG(SRC_BSISR, 0x238, 0x40), RSND_GEN_M_REG(SRC_BSISR, 0x238, 0x40),
RSND_GEN_M_REG(CTU_SWRSR, 0x500, 0x100),
RSND_GEN_M_REG(CTU_CTUIR, 0x504, 0x100), RSND_GEN_M_REG(CTU_CTUIR, 0x504, 0x100),
RSND_GEN_M_REG(CTU_ADINR, 0x508, 0x100), RSND_GEN_M_REG(CTU_ADINR, 0x508, 0x100),
RSND_GEN_M_REG(CTU_CPMDR, 0x510, 0x100),
RSND_GEN_M_REG(CTU_SCMDR, 0x514, 0x100),
RSND_GEN_M_REG(CTU_SV00R, 0x518, 0x100),
RSND_GEN_M_REG(CTU_SV01R, 0x51c, 0x100),
RSND_GEN_M_REG(CTU_SV02R, 0x520, 0x100),
RSND_GEN_M_REG(CTU_SV03R, 0x524, 0x100),
RSND_GEN_M_REG(CTU_SV04R, 0x528, 0x100),
RSND_GEN_M_REG(CTU_SV05R, 0x52c, 0x100),
RSND_GEN_M_REG(CTU_SV06R, 0x530, 0x100),
RSND_GEN_M_REG(CTU_SV07R, 0x534, 0x100),
RSND_GEN_M_REG(CTU_SV10R, 0x538, 0x100),
RSND_GEN_M_REG(CTU_SV11R, 0x53c, 0x100),
RSND_GEN_M_REG(CTU_SV12R, 0x540, 0x100),
RSND_GEN_M_REG(CTU_SV13R, 0x544, 0x100),
RSND_GEN_M_REG(CTU_SV14R, 0x548, 0x100),
RSND_GEN_M_REG(CTU_SV15R, 0x54c, 0x100),
RSND_GEN_M_REG(CTU_SV16R, 0x550, 0x100),
RSND_GEN_M_REG(CTU_SV17R, 0x554, 0x100),
RSND_GEN_M_REG(CTU_SV20R, 0x558, 0x100),
RSND_GEN_M_REG(CTU_SV21R, 0x55c, 0x100),
RSND_GEN_M_REG(CTU_SV22R, 0x560, 0x100),
RSND_GEN_M_REG(CTU_SV23R, 0x564, 0x100),
RSND_GEN_M_REG(CTU_SV24R, 0x568, 0x100),
RSND_GEN_M_REG(CTU_SV25R, 0x56c, 0x100),
RSND_GEN_M_REG(CTU_SV26R, 0x570, 0x100),
RSND_GEN_M_REG(CTU_SV27R, 0x574, 0x100),
RSND_GEN_M_REG(CTU_SV30R, 0x578, 0x100),
RSND_GEN_M_REG(CTU_SV31R, 0x57c, 0x100),
RSND_GEN_M_REG(CTU_SV32R, 0x580, 0x100),
RSND_GEN_M_REG(CTU_SV33R, 0x584, 0x100),
RSND_GEN_M_REG(CTU_SV34R, 0x588, 0x100),
RSND_GEN_M_REG(CTU_SV35R, 0x58c, 0x100),
RSND_GEN_M_REG(CTU_SV36R, 0x590, 0x100),
RSND_GEN_M_REG(CTU_SV37R, 0x594, 0x100),
RSND_GEN_M_REG(MIX_SWRSR, 0xd00, 0x40), RSND_GEN_M_REG(MIX_SWRSR, 0xd00, 0x40),
RSND_GEN_M_REG(MIX_MIXIR, 0xd04, 0x40), RSND_GEN_M_REG(MIX_MIXIR, 0xd04, 0x40),
RSND_GEN_M_REG(MIX_ADINR, 0xd08, 0x40), RSND_GEN_M_REG(MIX_ADINR, 0xd08, 0x40),
......
...@@ -51,7 +51,7 @@ static void rsnd_mix_volume_init(struct rsnd_dai_stream *io, ...@@ -51,7 +51,7 @@ static void rsnd_mix_volume_init(struct rsnd_dai_stream *io,
rsnd_mod_write(mod, MIX_MIXIR, 1); rsnd_mod_write(mod, MIX_MIXIR, 1);
/* General Information */ /* General Information */
rsnd_mod_write(mod, MIX_ADINR, rsnd_get_adinr_chan(mod, io)); rsnd_mod_write(mod, MIX_ADINR, rsnd_runtime_channel_after_ctu(io));
/* volume step */ /* volume step */
rsnd_mod_write(mod, MIX_MIXMR, 0); rsnd_mod_write(mod, MIX_MIXMR, 0);
...@@ -172,7 +172,7 @@ int rsnd_mix_probe(struct rsnd_priv *priv) ...@@ -172,7 +172,7 @@ int rsnd_mix_probe(struct rsnd_priv *priv)
} }
ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops, ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops,
clk, RSND_MOD_MIX, i); clk, rsnd_mod_get_status, RSND_MOD_MIX, i);
if (ret) if (ret)
goto rsnd_mix_probe_done; goto rsnd_mix_probe_done;
......
...@@ -86,8 +86,43 @@ enum rsnd_reg { ...@@ -86,8 +86,43 @@ enum rsnd_reg {
RSND_REG_CMD_BUSIF_DALIGN, /* Gen2 only */ RSND_REG_CMD_BUSIF_DALIGN, /* Gen2 only */
RSND_REG_CMD_ROUTE_SLCT, RSND_REG_CMD_ROUTE_SLCT,
RSND_REG_CMDOUT_TIMSEL, /* Gen2 only */ RSND_REG_CMDOUT_TIMSEL, /* Gen2 only */
RSND_REG_CTU_SWRSR,
RSND_REG_CTU_CTUIR, RSND_REG_CTU_CTUIR,
RSND_REG_CTU_ADINR, RSND_REG_CTU_ADINR,
RSND_REG_CTU_CPMDR,
RSND_REG_CTU_SCMDR,
RSND_REG_CTU_SV00R,
RSND_REG_CTU_SV01R,
RSND_REG_CTU_SV02R,
RSND_REG_CTU_SV03R,
RSND_REG_CTU_SV04R,
RSND_REG_CTU_SV05R,
RSND_REG_CTU_SV06R,
RSND_REG_CTU_SV07R,
RSND_REG_CTU_SV10R,
RSND_REG_CTU_SV11R,
RSND_REG_CTU_SV12R,
RSND_REG_CTU_SV13R,
RSND_REG_CTU_SV14R,
RSND_REG_CTU_SV15R,
RSND_REG_CTU_SV16R,
RSND_REG_CTU_SV17R,
RSND_REG_CTU_SV20R,
RSND_REG_CTU_SV21R,
RSND_REG_CTU_SV22R,
RSND_REG_CTU_SV23R,
RSND_REG_CTU_SV24R,
RSND_REG_CTU_SV25R,
RSND_REG_CTU_SV26R,
RSND_REG_CTU_SV27R,
RSND_REG_CTU_SV30R,
RSND_REG_CTU_SV31R,
RSND_REG_CTU_SV32R,
RSND_REG_CTU_SV33R,
RSND_REG_CTU_SV34R,
RSND_REG_CTU_SV35R,
RSND_REG_CTU_SV36R,
RSND_REG_CTU_SV37R,
RSND_REG_MIX_SWRSR, RSND_REG_MIX_SWRSR,
RSND_REG_MIX_MIXIR, RSND_REG_MIX_MIXIR,
RSND_REG_MIX_ADINR, RSND_REG_MIX_ADINR,
...@@ -147,8 +182,6 @@ struct rsnd_dai_stream; ...@@ -147,8 +182,6 @@ struct rsnd_dai_stream;
rsnd_read(rsnd_mod_to_priv(m), m, RSND_REG_##r) rsnd_read(rsnd_mod_to_priv(m), m, RSND_REG_##r)
#define rsnd_mod_write(m, r, d) \ #define rsnd_mod_write(m, r, d) \
rsnd_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d) rsnd_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d)
#define rsnd_mod_force_write(m, r, d) \
rsnd_force_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d)
#define rsnd_mod_bset(m, r, s, d) \ #define rsnd_mod_bset(m, r, s, d) \
rsnd_bset(rsnd_mod_to_priv(m), m, RSND_REG_##r, s, d) rsnd_bset(rsnd_mod_to_priv(m), m, RSND_REG_##r, s, d)
...@@ -160,14 +193,13 @@ void rsnd_force_write(struct rsnd_priv *priv, struct rsnd_mod *mod, ...@@ -160,14 +193,13 @@ void rsnd_force_write(struct rsnd_priv *priv, struct rsnd_mod *mod,
void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg,
u32 mask, u32 data); u32 mask, u32 data);
u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io); u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io); u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
/* /*
* R-Car DMA * R-Car DMA
*/ */
struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io, int rsnd_dma_attach(struct rsnd_dai_stream *io,
struct rsnd_mod *mod, int id); struct rsnd_mod *mod, struct rsnd_mod **dma_mod, int id);
int rsnd_dma_probe(struct rsnd_priv *priv); int rsnd_dma_probe(struct rsnd_priv *priv);
struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
struct rsnd_mod *mod, char *name); struct rsnd_mod *mod, char *name);
...@@ -214,6 +246,9 @@ struct rsnd_mod_ops { ...@@ -214,6 +246,9 @@ struct rsnd_mod_ops {
int (*stop)(struct rsnd_mod *mod, int (*stop)(struct rsnd_mod *mod,
struct rsnd_dai_stream *io, struct rsnd_dai_stream *io,
struct rsnd_priv *priv); struct rsnd_priv *priv);
int (*irq)(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv, int enable);
int (*pcm_new)(struct rsnd_mod *mod, int (*pcm_new)(struct rsnd_mod *mod,
struct rsnd_dai_stream *io, struct rsnd_dai_stream *io,
struct snd_soc_pcm_runtime *rtd); struct snd_soc_pcm_runtime *rtd);
...@@ -233,47 +268,54 @@ struct rsnd_mod { ...@@ -233,47 +268,54 @@ struct rsnd_mod {
struct rsnd_mod_ops *ops; struct rsnd_mod_ops *ops;
struct rsnd_priv *priv; struct rsnd_priv *priv;
struct clk *clk; struct clk *clk;
u32 *(*get_status)(struct rsnd_dai_stream *io,
struct rsnd_mod *mod,
enum rsnd_mod_type type);
u32 status;
}; };
/* /*
* status * status
* *
* 0xH0000CBA * 0xH0000CB0
* *
* A 0: probe 1: remove
* B 0: init 1: quit * B 0: init 1: quit
* C 0: start 1: stop * C 0: start 1: stop
* *
* H is always called (see __rsnd_mod_call) * H is always called (see __rsnd_mod_call)
* H 0: probe 1: remove
* H 0: pcm_new * H 0: pcm_new
* H 0: fallback * H 0: fallback
* H 0: hw_params * H 0: hw_params
*/ */
#define __rsnd_mod_shift_probe 0
#define __rsnd_mod_shift_remove 0
#define __rsnd_mod_shift_init 4 #define __rsnd_mod_shift_init 4
#define __rsnd_mod_shift_quit 4 #define __rsnd_mod_shift_quit 4
#define __rsnd_mod_shift_start 8 #define __rsnd_mod_shift_start 8
#define __rsnd_mod_shift_stop 8 #define __rsnd_mod_shift_stop 8
#define __rsnd_mod_shift_probe 28 /* always called */
#define __rsnd_mod_shift_remove 28 /* always called */
#define __rsnd_mod_shift_irq 28 /* always called */
#define __rsnd_mod_shift_pcm_new 28 /* always called */ #define __rsnd_mod_shift_pcm_new 28 /* always called */
#define __rsnd_mod_shift_fallback 28 /* always called */ #define __rsnd_mod_shift_fallback 28 /* always called */
#define __rsnd_mod_shift_hw_params 28 /* always called */ #define __rsnd_mod_shift_hw_params 28 /* always called */
#define __rsnd_mod_add_probe 1 #define __rsnd_mod_add_probe 0
#define __rsnd_mod_add_remove -1 #define __rsnd_mod_add_remove 0
#define __rsnd_mod_add_init 1 #define __rsnd_mod_add_init 1
#define __rsnd_mod_add_quit -1 #define __rsnd_mod_add_quit -1
#define __rsnd_mod_add_start 1 #define __rsnd_mod_add_start 1
#define __rsnd_mod_add_stop -1 #define __rsnd_mod_add_stop -1
#define __rsnd_mod_add_irq 0
#define __rsnd_mod_add_pcm_new 0 #define __rsnd_mod_add_pcm_new 0
#define __rsnd_mod_add_fallback 0 #define __rsnd_mod_add_fallback 0
#define __rsnd_mod_add_hw_params 0 #define __rsnd_mod_add_hw_params 0
#define __rsnd_mod_call_probe 0 #define __rsnd_mod_call_probe 0
#define __rsnd_mod_call_remove 1 #define __rsnd_mod_call_remove 0
#define __rsnd_mod_call_init 0 #define __rsnd_mod_call_init 0
#define __rsnd_mod_call_quit 1 #define __rsnd_mod_call_quit 1
#define __rsnd_mod_call_start 0 #define __rsnd_mod_call_start 0
#define __rsnd_mod_call_stop 1 #define __rsnd_mod_call_stop 1
#define __rsnd_mod_call_irq 0
#define __rsnd_mod_call_pcm_new 0 #define __rsnd_mod_call_pcm_new 0
#define __rsnd_mod_call_fallback 0 #define __rsnd_mod_call_fallback 0
#define __rsnd_mod_call_hw_params 0 #define __rsnd_mod_call_hw_params 0
...@@ -286,10 +328,13 @@ struct rsnd_mod { ...@@ -286,10 +328,13 @@ struct rsnd_mod {
int rsnd_mod_init(struct rsnd_priv *priv, int rsnd_mod_init(struct rsnd_priv *priv,
struct rsnd_mod *mod, struct rsnd_mod *mod,
struct rsnd_mod_ops *ops, struct rsnd_mod_ops *ops,
struct clk *clk, struct clk *clk,
enum rsnd_mod_type type, u32* (*get_status)(struct rsnd_dai_stream *io,
int id); struct rsnd_mod *mod,
enum rsnd_mod_type type),
enum rsnd_mod_type type,
int id);
void rsnd_mod_quit(struct rsnd_mod *mod); void rsnd_mod_quit(struct rsnd_mod *mod);
char *rsnd_mod_name(struct rsnd_mod *mod); char *rsnd_mod_name(struct rsnd_mod *mod);
struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io, struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
...@@ -297,6 +342,10 @@ struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io, ...@@ -297,6 +342,10 @@ struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
void rsnd_mod_interrupt(struct rsnd_mod *mod, void rsnd_mod_interrupt(struct rsnd_mod *mod,
void (*callback)(struct rsnd_mod *mod, void (*callback)(struct rsnd_mod *mod,
struct rsnd_dai_stream *io)); struct rsnd_dai_stream *io));
u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io,
struct rsnd_mod *mod,
enum rsnd_mod_type type);
void rsnd_parse_connect_common(struct rsnd_dai *rdai, void rsnd_parse_connect_common(struct rsnd_dai *rdai,
struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id), struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id),
struct device_node *node, struct device_node *node,
...@@ -306,9 +355,14 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai, ...@@ -306,9 +355,14 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai,
void rsnd_set_slot(struct rsnd_dai *rdai, void rsnd_set_slot(struct rsnd_dai *rdai,
int slots, int slots_total); int slots, int slots_total);
int rsnd_get_slot(struct rsnd_dai_stream *io); int rsnd_get_slot(struct rsnd_dai_stream *io);
int rsnd_get_slot_width(struct rsnd_dai_stream *io);
int rsnd_get_slot_num(struct rsnd_dai_stream *io); int rsnd_get_slot_num(struct rsnd_dai_stream *io);
int rsnd_runtime_channel_original(struct rsnd_dai_stream *io);
int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io);
int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io);
int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io);
int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io);
/* /*
* R-Car sound DAI * R-Car sound DAI
*/ */
...@@ -319,7 +373,7 @@ struct rsnd_dai_stream { ...@@ -319,7 +373,7 @@ struct rsnd_dai_stream {
struct rsnd_mod *mod[RSND_MOD_MAX]; struct rsnd_mod *mod[RSND_MOD_MAX];
struct rsnd_dai_path_info *info; /* rcar_snd.h */ struct rsnd_dai_path_info *info; /* rcar_snd.h */
struct rsnd_dai *rdai; struct rsnd_dai *rdai;
u32 mod_status[RSND_MOD_MAX]; u32 parent_ssi_status;
int byte_pos; int byte_pos;
int period_pos; int period_pos;
int byte_per_period; int byte_per_period;
...@@ -392,12 +446,10 @@ int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod); ...@@ -392,12 +446,10 @@ int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod);
int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate); int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate);
int rsnd_adg_probe(struct rsnd_priv *priv); int rsnd_adg_probe(struct rsnd_priv *priv);
void rsnd_adg_remove(struct rsnd_priv *priv); void rsnd_adg_remove(struct rsnd_priv *priv);
int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod, int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod,
struct rsnd_dai_stream *io, struct rsnd_dai_stream *io,
unsigned int src_rate, unsigned int in_rate,
unsigned int dst_rate); unsigned int out_rate);
int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *mod,
struct rsnd_dai_stream *io);
int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod, int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod,
struct rsnd_dai_stream *io); struct rsnd_dai_stream *io);
...@@ -498,10 +550,10 @@ struct rsnd_kctrl_cfg { ...@@ -498,10 +550,10 @@ struct rsnd_kctrl_cfg {
struct snd_kcontrol *kctrl; struct snd_kcontrol *kctrl;
}; };
#define RSND_DVC_CHANNELS 8 #define RSND_MAX_CHANNELS 8
struct rsnd_kctrl_cfg_m { struct rsnd_kctrl_cfg_m {
struct rsnd_kctrl_cfg cfg; struct rsnd_kctrl_cfg cfg;
u32 val[RSND_DVC_CHANNELS]; u32 val[RSND_MAX_CHANNELS];
}; };
struct rsnd_kctrl_cfg_s { struct rsnd_kctrl_cfg_s {
...@@ -547,7 +599,7 @@ void rsnd_ssi_remove(struct rsnd_priv *priv); ...@@ -547,7 +599,7 @@ void rsnd_ssi_remove(struct rsnd_priv *priv);
struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
int rsnd_ssi_use_busif(struct rsnd_dai_stream *io); int rsnd_ssi_use_busif(struct rsnd_dai_stream *io);
u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io); u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io);
#define rsnd_ssi_is_pin_sharing(io) \ #define rsnd_ssi_is_pin_sharing(io) \
__rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io)) __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io))
...@@ -573,9 +625,13 @@ void rsnd_ssiu_remove(struct rsnd_priv *priv); ...@@ -573,9 +625,13 @@ void rsnd_ssiu_remove(struct rsnd_priv *priv);
int rsnd_src_probe(struct rsnd_priv *priv); int rsnd_src_probe(struct rsnd_priv *priv);
void rsnd_src_remove(struct rsnd_priv *priv); void rsnd_src_remove(struct rsnd_priv *priv);
struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id); struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id);
unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
struct rsnd_dai_stream *io, #define rsnd_src_get_in_rate(priv, io) rsnd_src_get_rate(priv, io, 1)
struct snd_pcm_runtime *runtime); #define rsnd_src_get_out_rate(priv, io) rsnd_src_get_rate(priv, io, 0)
unsigned int rsnd_src_get_rate(struct rsnd_priv *priv,
struct rsnd_dai_stream *io,
int is_in);
#define rsnd_src_of_node(priv) \ #define rsnd_src_of_node(priv) \
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src") of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src")
#define rsnd_parse_connect_src(rdai, playback, capture) \ #define rsnd_parse_connect_src(rdai, playback, capture) \
...@@ -588,6 +644,7 @@ unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, ...@@ -588,6 +644,7 @@ unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
*/ */
int rsnd_ctu_probe(struct rsnd_priv *priv); int rsnd_ctu_probe(struct rsnd_priv *priv);
void rsnd_ctu_remove(struct rsnd_priv *priv); void rsnd_ctu_remove(struct rsnd_priv *priv);
int rsnd_ctu_converted_channel(struct rsnd_mod *mod);
struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id);
#define rsnd_ctu_of_node(priv) \ #define rsnd_ctu_of_node(priv) \
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ctu") of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ctu")
......
...@@ -66,12 +66,12 @@ struct rsrc_card_priv { ...@@ -66,12 +66,12 @@ struct rsrc_card_priv {
struct snd_soc_dai_link *dai_link; struct snd_soc_dai_link *dai_link;
int dai_num; int dai_num;
u32 convert_rate; u32 convert_rate;
u32 convert_channels;
}; };
#define rsrc_priv_to_dev(priv) ((priv)->snd_card.dev) #define rsrc_priv_to_dev(priv) ((priv)->snd_card.dev)
#define rsrc_priv_to_link(priv, i) ((priv)->snd_card.dai_link + (i)) #define rsrc_priv_to_link(priv, i) ((priv)->snd_card.dai_link + (i))
#define rsrc_priv_to_props(priv, i) ((priv)->dai_props + (i)) #define rsrc_priv_to_props(priv, i) ((priv)->dai_props + (i))
#define rsrc_dev_to_of_data(dev) (of_match_device(rsrc_card_of_match, (dev))->data)
static int rsrc_card_startup(struct snd_pcm_substream *substream) static int rsrc_card_startup(struct snd_pcm_substream *substream)
{ {
...@@ -145,11 +145,16 @@ static int rsrc_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, ...@@ -145,11 +145,16 @@ static int rsrc_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
struct snd_interval *rate = hw_param_interval(params, struct snd_interval *rate = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_RATE); SNDRV_PCM_HW_PARAM_RATE);
struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
if (!priv->convert_rate) if (priv->convert_rate)
return 0; rate->min =
rate->max = priv->convert_rate;
rate->min = rate->max = priv->convert_rate; if (priv->convert_channels)
channels->min =
channels->max = priv->convert_channels;
return 0; return 0;
} }
...@@ -246,7 +251,7 @@ static int rsrc_card_parse_links(struct device_node *np, ...@@ -246,7 +251,7 @@ static int rsrc_card_parse_links(struct device_node *np,
struct device *dev = rsrc_priv_to_dev(priv); struct device *dev = rsrc_priv_to_dev(priv);
const struct rsrc_card_of_data *of_data; const struct rsrc_card_of_data *of_data;
of_data = rsrc_dev_to_of_data(dev); of_data = of_device_get_match_data(dev);
/* FE is dummy */ /* FE is dummy */
dai_link->cpu_of_node = NULL; dai_link->cpu_of_node = NULL;
...@@ -396,7 +401,7 @@ static int rsrc_card_parse_of(struct device_node *node, ...@@ -396,7 +401,7 @@ static int rsrc_card_parse_of(struct device_node *node,
struct rsrc_card_priv *priv, struct rsrc_card_priv *priv,
struct device *dev) struct device *dev)
{ {
const struct rsrc_card_of_data *of_data = rsrc_dev_to_of_data(dev); const struct rsrc_card_of_data *of_data = of_device_get_match_data(dev);
struct rsrc_card_dai *props; struct rsrc_card_dai *props;
struct snd_soc_dai_link *links; struct snd_soc_dai_link *links;
int ret; int ret;
...@@ -437,9 +442,13 @@ static int rsrc_card_parse_of(struct device_node *node, ...@@ -437,9 +442,13 @@ static int rsrc_card_parse_of(struct device_node *node,
/* sampling rate convert */ /* sampling rate convert */
of_property_read_u32(node, "convert-rate", &priv->convert_rate); of_property_read_u32(node, "convert-rate", &priv->convert_rate);
dev_dbg(dev, "New rsrc-audio-card: %s (%d)\n", /* channels transfer */
priv->snd_card.name ? priv->snd_card.name : "", of_property_read_u32(node, "convert-channels", &priv->convert_channels);
priv->convert_rate);
dev_dbg(dev, "New rsrc-audio-card: %s\n",
priv->snd_card.name ? priv->snd_card.name : "");
dev_dbg(dev, "SRC : convert_rate %d\n", priv->convert_rate);
dev_dbg(dev, "CTU : convert_channels %d\n", priv->convert_channels);
ret = rsrc_card_dai_link_of(node, priv); ret = rsrc_card_dai_link_of(node, priv);
if (ret < 0) if (ret < 0)
......
This diff is collapsed.
This diff is collapsed.
...@@ -27,7 +27,7 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod, ...@@ -27,7 +27,7 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod,
struct rsnd_priv *priv) struct rsnd_priv *priv)
{ {
struct rsnd_dai *rdai = rsnd_io_to_rdai(io); struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
u32 multi_ssi_slaves = rsnd_ssi_multi_slaves(io); u32 multi_ssi_slaves = rsnd_ssi_multi_slaves_runtime(io);
int use_busif = rsnd_ssi_use_busif(io); int use_busif = rsnd_ssi_use_busif(io);
int id = rsnd_mod_id(mod); int id = rsnd_mod_id(mod);
u32 mask1, val1; u32 mask1, val1;
...@@ -105,7 +105,7 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, ...@@ -105,7 +105,7 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
if (ret < 0) if (ret < 0)
return ret; return ret;
if (rsnd_get_slot_width(io) >= 6) { if (rsnd_runtime_is_ssi_tdm(io)) {
/* /*
* TDM Extend Mode * TDM Extend Mode
* see * see
...@@ -115,13 +115,14 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, ...@@ -115,13 +115,14 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
} }
if (rsnd_ssi_use_busif(io)) { if (rsnd_ssi_use_busif(io)) {
u32 val = rsnd_get_dalign(mod, io);
rsnd_mod_write(mod, SSI_BUSIF_ADINR, rsnd_mod_write(mod, SSI_BUSIF_ADINR,
rsnd_get_adinr_bit(mod, io) | rsnd_get_adinr_bit(mod, io) |
rsnd_get_adinr_chan(mod, io)); (rsnd_io_is_play(io) ?
rsnd_runtime_channel_after_ctu(io) :
rsnd_runtime_channel_original(io)));
rsnd_mod_write(mod, SSI_BUSIF_MODE, 1); rsnd_mod_write(mod, SSI_BUSIF_MODE, 1);
rsnd_mod_write(mod, SSI_BUSIF_DALIGN, val); rsnd_mod_write(mod, SSI_BUSIF_DALIGN,
rsnd_get_dalign(mod, io));
} }
return 0; return 0;
...@@ -136,7 +137,7 @@ static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod, ...@@ -136,7 +137,7 @@ static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod,
rsnd_mod_write(mod, SSI_CTRL, 0x1); rsnd_mod_write(mod, SSI_CTRL, 0x1);
if (rsnd_ssi_multi_slaves(io)) if (rsnd_ssi_multi_slaves_runtime(io))
rsnd_mod_write(mod, SSI_CONTROL, 0x1); rsnd_mod_write(mod, SSI_CONTROL, 0x1);
return 0; return 0;
...@@ -151,7 +152,7 @@ static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod, ...@@ -151,7 +152,7 @@ static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod,
rsnd_mod_write(mod, SSI_CTRL, 0); rsnd_mod_write(mod, SSI_CTRL, 0);
if (rsnd_ssi_multi_slaves(io)) if (rsnd_ssi_multi_slaves_runtime(io))
rsnd_mod_write(mod, SSI_CONTROL, 0); rsnd_mod_write(mod, SSI_CONTROL, 0);
return 0; return 0;
...@@ -206,7 +207,8 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv) ...@@ -206,7 +207,8 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv)
for_each_rsnd_ssiu(ssiu, priv, i) { for_each_rsnd_ssiu(ssiu, priv, i) {
ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu), ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu),
ops, NULL, RSND_MOD_SSIU, i); ops, NULL, rsnd_mod_get_status,
RSND_MOD_SSIU, i);
if (ret) if (ret)
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment