Commit cb6bfd3d authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'asoc/topic/rx51', 'asoc/topic/samsung',...

Merge remote-tracking branches 'asoc/topic/rx51', 'asoc/topic/samsung', 'asoc/topic/sh', 'asoc/topic/simple' and 'asoc/topic/sta32x' into asoc-next
...@@ -33,6 +33,25 @@ Required SoC Specific Properties: ...@@ -33,6 +33,25 @@ Required SoC Specific Properties:
"iis" is the i2s bus clock and i2s_opclk0, i2s_opclk1 are sources of the root "iis" is the i2s bus clock and i2s_opclk0, i2s_opclk1 are sources of the root
clk. i2s0 has internal mux to select the source of root clk and i2s1 and i2s2 clk. i2s0 has internal mux to select the source of root clk and i2s1 and i2s2
doesn't have any such mux. doesn't have any such mux.
- #clock-cells: should be 1, this property must be present if the I2S device
is a clock provider in terms of the common clock bindings, described in
../clock/clock-bindings.txt.
- clock-output-names: from the common clock bindings, names of the CDCLK
I2S output clocks, suggested values are "i2s_cdclk0", "i2s_cdclk1",
"i2s_cdclk3" for the I2S0, I2S1, I2S2 devices recpectively.
There are following clocks available at the I2S device nodes:
CLK_I2S_CDCLK - the CDCLK (CODECLKO) gate clock,
CLK_I2S_RCLK_PSR - the RCLK prescaler divider clock (corresponding to the
IISPSR register),
CLK_I2S_RCLK_SRC - the RCLKSRC mux clock (corresponding to RCLKSRC bit in
IISMOD register).
Refer to the SoC datasheet for availability of the above clocks.
The CLK_I2S_RCLK_PSR and CLK_I2S_RCLK_SRC clocks are usually only available
in the IIS Multi Audio Interface (I2S0).
Note: Old DTs may not have the #clock-cells, clock-output-names properties
and then not use the I2S node as a clock supplier.
Optional SoC Specific Properties: Optional SoC Specific Properties:
...@@ -41,6 +60,7 @@ Optional SoC Specific Properties: ...@@ -41,6 +60,7 @@ Optional SoC Specific Properties:
- pinctrl-0: Should specify pin control groups used for this controller. - pinctrl-0: Should specify pin control groups used for this controller.
- pinctrl-names: Should contain only one value - "default". - pinctrl-names: Should contain only one value - "default".
Example: Example:
i2s0: i2s@03830000 { i2s0: i2s@03830000 {
...@@ -54,6 +74,8 @@ i2s0: i2s@03830000 { ...@@ -54,6 +74,8 @@ i2s0: i2s@03830000 {
<&clock_audss EXYNOS_I2S_BUS>, <&clock_audss EXYNOS_I2S_BUS>,
<&clock_audss EXYNOS_SCLK_I2S>; <&clock_audss EXYNOS_SCLK_I2S>;
clock-names = "iis", "i2s_opclk0", "i2s_opclk1"; clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
#clock-cells;
clock-output-names = "i2s_cdclk0";
samsung,idma-addr = <0x03000000>; samsung,idma-addr = <0x03000000>;
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&i2s0_bus>; pinctrl-0 = <&i2s0_bus>;
......
...@@ -75,6 +75,11 @@ Optional CPU/CODEC subnodes properties: ...@@ -75,6 +75,11 @@ Optional CPU/CODEC subnodes properties:
it can be specified via "clocks" if system has it can be specified via "clocks" if system has
clock node (= common clock), or "system-clock-frequency" clock node (= common clock), or "system-clock-frequency"
(if system doens't support common clock) (if system doens't support common clock)
If a clock is specified, it is
enabled with clk_prepare_enable()
in dai startup() and disabled with
clk_disable_unprepare() in dai
shutdown().
Example 1 - single DAI link: Example 1 - single DAI link:
......
STA32X audio CODEC
The driver for this device only supports I2C.
Required properties:
- compatible: "st,sta32x"
- reg: the I2C address of the device for I2C
- reset-gpios: a GPIO spec for the reset pin. If specified, it will be
deasserted before communication to the codec starts.
- power-down-gpios: a GPIO spec for the power down pin. If specified,
it will be deasserted before communication to the codec
starts.
- Vdda-supply: regulator spec, providing 3.3V
- Vdd3-supply: regulator spec, providing 3.3V
- Vcc-supply: regulator spec, providing 5V - 26V
Optional properties:
- st,output-conf: number, Selects the output configuration:
0: 2-channel (full-bridge) power, 2-channel data-out
1: 2 (half-bridge). 1 (full-bridge) on-board power
2: 2 Channel (Full-Bridge) Power, 1 Channel FFX
3: 1 Channel Mono-Parallel
If parameter is missing, mode 0 will be enabled.
This property has to be specified as '/bits/ 8' value.
- st,ch1-output-mapping: Channel 1 output mapping
- st,ch2-output-mapping: Channel 2 output mapping
- st,ch3-output-mapping: Channel 3 output mapping
0: Channel 1
1: Channel 2
2: Channel 3
If parameter is missing, channel 1 is chosen.
This properties have to be specified as '/bits/ 8' values.
- st,thermal-warning-recover:
If present, thermal warning recovery is enabled.
- st,thermal-warning-adjustment:
If present, thermal warning adjustment is enabled.
- st,fault-detect-recovery:
If present, then fault recovery will be enabled.
- st,drop-compensation-ns: number
Only required for "st,ffx-power-output-mode" ==
"variable-drop-compensation".
Specifies the drop compensation in nanoseconds.
The value must be in the range of 0..300, and only
multiples of 20 are allowed. Default is 140ns.
- st,max-power-use-mpcc:
If present, then MPCC bits are used for MPC coefficients,
otherwise standard MPC coefficients are used.
- st,max-power-corr:
If present, power bridge correction for THD reduction near maximum
power output is enabled.
- st,am-reduction-mode:
If present, FFX mode runs in AM reduction mode, otherwise normal
FFX mode is used.
- st,odd-pwm-speed-mode:
If present, PWM speed mode run on odd speed mode (341.3 kHz) on all
channels. If not present, normal PWM spped mode (384 kHz) will be used.
- st,invalid-input-detect-mute:
If present, automatic invalid input detect mute is enabled.
Example:
codec: sta32x@38 {
compatible = "st,sta32x";
reg = <0x1c>;
reset-gpios = <&gpio1 19 0>;
power-down-gpios = <&gpio1 16 0>;
st,output-conf = /bits/ 8 <0x3>; // set output to 2-channel
// (full-bridge) power,
// 2-channel data-out
st,ch1-output-mapping = /bits/ 8 <0>; // set channel 1 output ch 1
st,ch2-output-mapping = /bits/ 8 <0>; // set channel 2 output ch 1
st,ch3-output-mapping = /bits/ 8 <0>; // set channel 3 output ch 1
st,max-power-correction; // enables power bridge
// correction for THD reduction
// near maximum power output
st,invalid-input-detect-mute; // mute if no valid digital
// audio signal is provided.
};
#ifndef _DT_BINDINGS_SAMSUNG_I2S_H
#define _DT_BINDINGS_SAMSUNG_I2S_H
#define CLK_I2S_CDCLK 0
#define CLK_I2S_RCLK_SRC 1
#define CLK_I2S_RCLK_PSR 2
#endif /* _DT_BINDINGS_SAMSUNG_I2S_H */
...@@ -20,6 +20,7 @@ struct asoc_simple_dai { ...@@ -20,6 +20,7 @@ struct asoc_simple_dai {
unsigned int sysclk; unsigned int sysclk;
int slots; int slots;
int slot_width; int slot_width;
struct clk *clk;
}; };
struct asoc_simple_card_info { struct asoc_simple_card_info {
......
...@@ -24,12 +24,20 @@ ...@@ -24,12 +24,20 @@
#define STA32X_THERMAL_RECOVERY_ENABLE 2 #define STA32X_THERMAL_RECOVERY_ENABLE 2
struct sta32x_platform_data { struct sta32x_platform_data {
int output_conf; u8 output_conf;
int ch1_output_mapping; u8 ch1_output_mapping;
int ch2_output_mapping; u8 ch2_output_mapping;
int ch3_output_mapping; u8 ch3_output_mapping;
int thermal_conf;
int needs_esd_watchdog; int needs_esd_watchdog;
u8 drop_compensation_ns;
unsigned int thermal_warning_recovery:1;
unsigned int thermal_warning_adjustment:1;
unsigned int fault_detect_recovery:1;
unsigned int max_power_use_mpcc:1;
unsigned int max_power_correction:1;
unsigned int am_reduction_mode:1;
unsigned int odd_pwm_speed_mode:1;
unsigned int invalid_input_detect_mute:1;
}; };
#endif /* __LINUX_SND__STA32X_H */ #endif /* __LINUX_SND__STA32X_H */
...@@ -580,7 +580,9 @@ config SND_SOC_SSM4567 ...@@ -580,7 +580,9 @@ config SND_SOC_SSM4567
depends on I2C depends on I2C
config SND_SOC_STA32X config SND_SOC_STA32X
tristate tristate "STA326, STA328 and STA329 speaker amplifier"
depends on I2C
select REGMAP_I2C
config SND_SOC_STA350 config SND_SOC_STA350
tristate "STA350 speaker amplifier" tristate "STA350 speaker amplifier"
......
...@@ -24,8 +24,11 @@ ...@@ -24,8 +24,11 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/gpio/consumer.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <sound/core.h> #include <sound/core.h>
...@@ -102,6 +105,35 @@ static const struct reg_default sta32x_regs[] = { ...@@ -102,6 +105,35 @@ static const struct reg_default sta32x_regs[] = {
{ 0x2c, 0x0c }, { 0x2c, 0x0c },
}; };
static const struct regmap_range sta32x_write_regs_range[] = {
regmap_reg_range(STA32X_CONFA, STA32X_AUTO2),
regmap_reg_range(STA32X_C1CFG, STA32X_FDRC2),
};
static const struct regmap_range sta32x_read_regs_range[] = {
regmap_reg_range(STA32X_CONFA, STA32X_AUTO2),
regmap_reg_range(STA32X_C1CFG, STA32X_FDRC2),
};
static const struct regmap_range sta32x_volatile_regs_range[] = {
regmap_reg_range(STA32X_CFADDR2, STA32X_CFUD),
};
static const struct regmap_access_table sta32x_write_regs = {
.yes_ranges = sta32x_write_regs_range,
.n_yes_ranges = ARRAY_SIZE(sta32x_write_regs_range),
};
static const struct regmap_access_table sta32x_read_regs = {
.yes_ranges = sta32x_read_regs_range,
.n_yes_ranges = ARRAY_SIZE(sta32x_read_regs_range),
};
static const struct regmap_access_table sta32x_volatile_regs = {
.yes_ranges = sta32x_volatile_regs_range,
.n_yes_ranges = ARRAY_SIZE(sta32x_volatile_regs_range),
};
/* regulator power supply names */ /* regulator power supply names */
static const char *sta32x_supply_names[] = { static const char *sta32x_supply_names[] = {
"Vdda", /* analog supply, 3.3VV */ "Vdda", /* analog supply, 3.3VV */
...@@ -122,6 +154,8 @@ struct sta32x_priv { ...@@ -122,6 +154,8 @@ struct sta32x_priv {
u32 coef_shadow[STA32X_COEF_COUNT]; u32 coef_shadow[STA32X_COEF_COUNT];
struct delayed_work watchdog_work; struct delayed_work watchdog_work;
int shutdown; int shutdown;
struct gpio_desc *gpiod_nreset;
struct mutex coeff_lock;
}; };
static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12700, 50, 1); static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12700, 50, 1);
...@@ -155,37 +189,32 @@ static const char *sta32x_limiter_release_rate[] = { ...@@ -155,37 +189,32 @@ static const char *sta32x_limiter_release_rate[] = {
"0.5116", "0.1370", "0.0744", "0.0499", "0.0360", "0.0299", "0.5116", "0.1370", "0.0744", "0.0499", "0.0360", "0.0299",
"0.0264", "0.0208", "0.0198", "0.0172", "0.0147", "0.0137", "0.0264", "0.0208", "0.0198", "0.0172", "0.0147", "0.0137",
"0.0134", "0.0117", "0.0110", "0.0104" }; "0.0134", "0.0117", "0.0110", "0.0104" };
static DECLARE_TLV_DB_RANGE(sta32x_limiter_ac_attack_tlv,
static const unsigned int sta32x_limiter_ac_attack_tlv[] = {
TLV_DB_RANGE_HEAD(2),
0, 7, TLV_DB_SCALE_ITEM(-1200, 200, 0), 0, 7, TLV_DB_SCALE_ITEM(-1200, 200, 0),
8, 16, TLV_DB_SCALE_ITEM(300, 100, 0), 8, 16, TLV_DB_SCALE_ITEM(300, 100, 0),
}; );
static const unsigned int sta32x_limiter_ac_release_tlv[] = { static DECLARE_TLV_DB_RANGE(sta32x_limiter_ac_release_tlv,
TLV_DB_RANGE_HEAD(5),
0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0), 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
1, 1, TLV_DB_SCALE_ITEM(-2900, 0, 0), 1, 1, TLV_DB_SCALE_ITEM(-2900, 0, 0),
2, 2, TLV_DB_SCALE_ITEM(-2000, 0, 0), 2, 2, TLV_DB_SCALE_ITEM(-2000, 0, 0),
3, 8, TLV_DB_SCALE_ITEM(-1400, 200, 0), 3, 8, TLV_DB_SCALE_ITEM(-1400, 200, 0),
8, 16, TLV_DB_SCALE_ITEM(-700, 100, 0), 8, 16, TLV_DB_SCALE_ITEM(-700, 100, 0),
}; );
static const unsigned int sta32x_limiter_drc_attack_tlv[] = { static DECLARE_TLV_DB_RANGE(sta32x_limiter_drc_attack_tlv,
TLV_DB_RANGE_HEAD(3),
0, 7, TLV_DB_SCALE_ITEM(-3100, 200, 0), 0, 7, TLV_DB_SCALE_ITEM(-3100, 200, 0),
8, 13, TLV_DB_SCALE_ITEM(-1600, 100, 0), 8, 13, TLV_DB_SCALE_ITEM(-1600, 100, 0),
14, 16, TLV_DB_SCALE_ITEM(-1000, 300, 0), 14, 16, TLV_DB_SCALE_ITEM(-1000, 300, 0),
}; );
static const unsigned int sta32x_limiter_drc_release_tlv[] = { static DECLARE_TLV_DB_RANGE(sta32x_limiter_drc_release_tlv,
TLV_DB_RANGE_HEAD(5),
0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0), 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
1, 2, TLV_DB_SCALE_ITEM(-3800, 200, 0), 1, 2, TLV_DB_SCALE_ITEM(-3800, 200, 0),
3, 4, TLV_DB_SCALE_ITEM(-3300, 200, 0), 3, 4, TLV_DB_SCALE_ITEM(-3300, 200, 0),
5, 12, TLV_DB_SCALE_ITEM(-3000, 200, 0), 5, 12, TLV_DB_SCALE_ITEM(-3000, 200, 0),
13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0), 13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0),
}; );
static SOC_ENUM_SINGLE_DECL(sta32x_drc_ac_enum, static SOC_ENUM_SINGLE_DECL(sta32x_drc_ac_enum,
STA32X_CONFD, STA32X_CONFD_DRC_SHIFT, STA32X_CONFD, STA32X_CONFD_DRC_SHIFT,
...@@ -244,29 +273,42 @@ static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol, ...@@ -244,29 +273,42 @@ static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
int numcoef = kcontrol->private_value >> 16; int numcoef = kcontrol->private_value >> 16;
int index = kcontrol->private_value & 0xffff; int index = kcontrol->private_value & 0xffff;
unsigned int cfud; unsigned int cfud, val;
int i; int i, ret = 0;
mutex_lock(&sta32x->coeff_lock);
/* preserve reserved bits in STA32X_CFUD */ /* preserve reserved bits in STA32X_CFUD */
cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0; regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
/* chip documentation does not say if the bits are self clearing, cfud &= 0xf0;
* so do it explicitly */ /*
snd_soc_write(codec, STA32X_CFUD, cfud); * chip documentation does not say if the bits are self clearing,
* so do it explicitly
*/
regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
snd_soc_write(codec, STA32X_CFADDR2, index); regmap_write(sta32x->regmap, STA32X_CFADDR2, index);
if (numcoef == 1) if (numcoef == 1) {
snd_soc_write(codec, STA32X_CFUD, cfud | 0x04); regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x04);
else if (numcoef == 5) } else if (numcoef == 5) {
snd_soc_write(codec, STA32X_CFUD, cfud | 0x08); regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x08);
else } else {
return -EINVAL; ret = -EINVAL;
for (i = 0; i < 3 * numcoef; i++) goto exit_unlock;
ucontrol->value.bytes.data[i] = }
snd_soc_read(codec, STA32X_B1CF1 + i);
return 0; for (i = 0; i < 3 * numcoef; i++) {
regmap_read(sta32x->regmap, STA32X_B1CF1 + i, &val);
ucontrol->value.bytes.data[i] = val;
}
exit_unlock:
mutex_unlock(&sta32x->coeff_lock);
return ret;
} }
static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol, static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,
...@@ -280,24 +322,27 @@ static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol, ...@@ -280,24 +322,27 @@ static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,
int i; int i;
/* preserve reserved bits in STA32X_CFUD */ /* preserve reserved bits in STA32X_CFUD */
cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0; regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
/* chip documentation does not say if the bits are self clearing, cfud &= 0xf0;
* so do it explicitly */ /*
snd_soc_write(codec, STA32X_CFUD, cfud); * chip documentation does not say if the bits are self clearing,
* so do it explicitly
*/
regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
snd_soc_write(codec, STA32X_CFADDR2, index); regmap_write(sta32x->regmap, STA32X_CFADDR2, index);
for (i = 0; i < numcoef && (index + i < STA32X_COEF_COUNT); i++) for (i = 0; i < numcoef && (index + i < STA32X_COEF_COUNT); i++)
sta32x->coef_shadow[index + i] = sta32x->coef_shadow[index + i] =
(ucontrol->value.bytes.data[3 * i] << 16) (ucontrol->value.bytes.data[3 * i] << 16)
| (ucontrol->value.bytes.data[3 * i + 1] << 8) | (ucontrol->value.bytes.data[3 * i + 1] << 8)
| (ucontrol->value.bytes.data[3 * i + 2]); | (ucontrol->value.bytes.data[3 * i + 2]);
for (i = 0; i < 3 * numcoef; i++) for (i = 0; i < 3 * numcoef; i++)
snd_soc_write(codec, STA32X_B1CF1 + i, regmap_write(sta32x->regmap, STA32X_B1CF1 + i,
ucontrol->value.bytes.data[i]); ucontrol->value.bytes.data[i]);
if (numcoef == 1) if (numcoef == 1)
snd_soc_write(codec, STA32X_CFUD, cfud | 0x01); regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x01);
else if (numcoef == 5) else if (numcoef == 5)
snd_soc_write(codec, STA32X_CFUD, cfud | 0x02); regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x02);
else else
return -EINVAL; return -EINVAL;
...@@ -311,20 +356,23 @@ static int sta32x_sync_coef_shadow(struct snd_soc_codec *codec) ...@@ -311,20 +356,23 @@ static int sta32x_sync_coef_shadow(struct snd_soc_codec *codec)
int i; int i;
/* preserve reserved bits in STA32X_CFUD */ /* preserve reserved bits in STA32X_CFUD */
cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0; regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
cfud &= 0xf0;
for (i = 0; i < STA32X_COEF_COUNT; i++) { for (i = 0; i < STA32X_COEF_COUNT; i++) {
snd_soc_write(codec, STA32X_CFADDR2, i); regmap_write(sta32x->regmap, STA32X_CFADDR2, i);
snd_soc_write(codec, STA32X_B1CF1, regmap_write(sta32x->regmap, STA32X_B1CF1,
(sta32x->coef_shadow[i] >> 16) & 0xff); (sta32x->coef_shadow[i] >> 16) & 0xff);
snd_soc_write(codec, STA32X_B1CF2, regmap_write(sta32x->regmap, STA32X_B1CF2,
(sta32x->coef_shadow[i] >> 8) & 0xff); (sta32x->coef_shadow[i] >> 8) & 0xff);
snd_soc_write(codec, STA32X_B1CF3, regmap_write(sta32x->regmap, STA32X_B1CF3,
(sta32x->coef_shadow[i]) & 0xff); (sta32x->coef_shadow[i]) & 0xff);
/* chip documentation does not say if the bits are /*
* self-clearing, so do it explicitly */ * chip documentation does not say if the bits are
snd_soc_write(codec, STA32X_CFUD, cfud); * self-clearing, so do it explicitly
snd_soc_write(codec, STA32X_CFUD, cfud | 0x01); */
regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x01);
} }
return 0; return 0;
} }
...@@ -336,11 +384,11 @@ static int sta32x_cache_sync(struct snd_soc_codec *codec) ...@@ -336,11 +384,11 @@ static int sta32x_cache_sync(struct snd_soc_codec *codec)
int rc; int rc;
/* mute during register sync */ /* mute during register sync */
mute = snd_soc_read(codec, STA32X_MMUTE); regmap_read(sta32x->regmap, STA32X_MMUTE, &mute);
snd_soc_write(codec, STA32X_MMUTE, mute | STA32X_MMUTE_MMUTE); regmap_write(sta32x->regmap, STA32X_MMUTE, mute | STA32X_MMUTE_MMUTE);
sta32x_sync_coef_shadow(codec); sta32x_sync_coef_shadow(codec);
rc = regcache_sync(sta32x->regmap); rc = regcache_sync(sta32x->regmap);
snd_soc_write(codec, STA32X_MMUTE, mute); regmap_write(sta32x->regmap, STA32X_MMUTE, mute);
return rc; return rc;
} }
...@@ -508,17 +556,12 @@ static struct { ...@@ -508,17 +556,12 @@ static struct {
}; };
/* MCLK to fs clock ratios */ /* MCLK to fs clock ratios */
static struct { static int mcs_ratio_table[3][7] = {
int ratio; { 768, 512, 384, 256, 128, 576, 0 },
int mcs; { 384, 256, 192, 128, 64, 0 },
} mclk_ratios[3][7] = { { 384, 256, 192, 128, 64, 0 },
{ { 768, 0 }, { 512, 1 }, { 384, 2 }, { 256, 3 },
{ 128, 4 }, { 576, 5 }, { 0, 0 } },
{ { 384, 2 }, { 256, 3 }, { 192, 4 }, { 128, 5 }, {64, 0 }, { 0, 0 } },
{ { 384, 2 }, { 256, 3 }, { 192, 4 }, { 128, 5 }, {64, 0 }, { 0, 0 } },
}; };
/** /**
* sta32x_set_dai_sysclk - configure MCLK * sta32x_set_dai_sysclk - configure MCLK
* @codec_dai: the codec DAI * @codec_dai: the codec DAI
...@@ -543,46 +586,10 @@ static int sta32x_set_dai_sysclk(struct snd_soc_dai *codec_dai, ...@@ -543,46 +586,10 @@ static int sta32x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
{ {
struct snd_soc_codec *codec = codec_dai->codec; struct snd_soc_codec *codec = codec_dai->codec;
struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
int i, j, ir, fs;
unsigned int rates = 0;
unsigned int rate_min = -1;
unsigned int rate_max = 0;
pr_debug("mclk=%u\n", freq); dev_dbg(codec->dev, "mclk=%u\n", freq);
sta32x->mclk = freq; sta32x->mclk = freq;
if (sta32x->mclk) {
for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) {
ir = interpolation_ratios[i].ir;
fs = interpolation_ratios[i].fs;
for (j = 0; mclk_ratios[ir][j].ratio; j++) {
if (mclk_ratios[ir][j].ratio * fs == freq) {
rates |= snd_pcm_rate_to_rate_bit(fs);
if (fs < rate_min)
rate_min = fs;
if (fs > rate_max)
rate_max = fs;
break;
}
}
}
/* FIXME: soc should support a rate list */
rates &= ~SNDRV_PCM_RATE_KNOT;
if (!rates) {
dev_err(codec->dev, "could not find a valid sample rate\n");
return -EINVAL;
}
} else {
/* enable all possible rates */
rates = STA32X_RATES;
rate_min = 32000;
rate_max = 192000;
}
codec_dai->driver->playback.rates = rates;
codec_dai->driver->playback.rate_min = rate_min;
codec_dai->driver->playback.rate_max = rate_max;
return 0; return 0;
} }
...@@ -599,10 +606,7 @@ static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai, ...@@ -599,10 +606,7 @@ static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai,
{ {
struct snd_soc_codec *codec = codec_dai->codec; struct snd_soc_codec *codec = codec_dai->codec;
struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
u8 confb = snd_soc_read(codec, STA32X_CONFB); u8 confb = 0;
pr_debug("\n");
confb &= ~(STA32X_CONFB_C1IM | STA32X_CONFB_C2IM);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS: case SND_SOC_DAIFMT_CBS_CFS:
...@@ -632,8 +636,8 @@ static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai, ...@@ -632,8 +636,8 @@ static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai,
return -EINVAL; return -EINVAL;
} }
snd_soc_write(codec, STA32X_CONFB, confb); return regmap_update_bits(sta32x->regmap, STA32X_CONFB,
return 0; STA32X_CONFB_C1IM | STA32X_CONFB_C2IM, confb);
} }
/** /**
...@@ -651,39 +655,55 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream, ...@@ -651,39 +655,55 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
{ {
struct snd_soc_codec *codec = dai->codec; struct snd_soc_codec *codec = dai->codec;
struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
unsigned int rate; int i, mcs = -EINVAL, ir = -EINVAL;
int i, mcs = -1, ir = -1; unsigned int confa, confb;
u8 confa, confb; unsigned int rate, ratio;
int ret;
if (!sta32x->mclk) {
dev_err(codec->dev,
"sta32x->mclk is unset. Unable to determine ratio\n");
return -EIO;
}
rate = params_rate(params); rate = params_rate(params);
pr_debug("rate: %u\n", rate); ratio = sta32x->mclk / rate;
for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) dev_dbg(codec->dev, "rate: %u, ratio: %u\n", rate, ratio);
for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) {
if (interpolation_ratios[i].fs == rate) { if (interpolation_ratios[i].fs == rate) {
ir = interpolation_ratios[i].ir; ir = interpolation_ratios[i].ir;
break; break;
} }
if (ir < 0) }
if (ir < 0) {
dev_err(codec->dev, "Unsupported samplerate: %u\n", rate);
return -EINVAL; return -EINVAL;
for (i = 0; mclk_ratios[ir][i].ratio; i++) }
if (mclk_ratios[ir][i].ratio * rate == sta32x->mclk) {
mcs = mclk_ratios[ir][i].mcs; for (i = 0; i < 6; i++) {
if (mcs_ratio_table[ir][i] == ratio) {
mcs = i;
break; break;
} }
if (mcs < 0) }
if (mcs < 0) {
dev_err(codec->dev, "Unresolvable ratio: %u\n", ratio);
return -EINVAL; return -EINVAL;
}
confa = snd_soc_read(codec, STA32X_CONFA); confa = (ir << STA32X_CONFA_IR_SHIFT) |
confa &= ~(STA32X_CONFA_MCS_MASK | STA32X_CONFA_IR_MASK); (mcs << STA32X_CONFA_MCS_SHIFT);
confa |= (ir << STA32X_CONFA_IR_SHIFT) | (mcs << STA32X_CONFA_MCS_SHIFT); confb = 0;
confb = snd_soc_read(codec, STA32X_CONFB);
confb &= ~(STA32X_CONFB_SAI_MASK | STA32X_CONFB_SAIFB);
switch (params_width(params)) { switch (params_width(params)) {
case 24: case 24:
pr_debug("24bit\n"); dev_dbg(codec->dev, "24bit\n");
/* fall through */ /* fall through */
case 32: case 32:
pr_debug("24bit or 32bit\n"); dev_dbg(codec->dev, "24bit or 32bit\n");
switch (sta32x->format) { switch (sta32x->format) {
case SND_SOC_DAIFMT_I2S: case SND_SOC_DAIFMT_I2S:
confb |= 0x0; confb |= 0x0;
...@@ -698,7 +718,7 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream, ...@@ -698,7 +718,7 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
break; break;
case 20: case 20:
pr_debug("20bit\n"); dev_dbg(codec->dev, "20bit\n");
switch (sta32x->format) { switch (sta32x->format) {
case SND_SOC_DAIFMT_I2S: case SND_SOC_DAIFMT_I2S:
confb |= 0x4; confb |= 0x4;
...@@ -713,7 +733,7 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream, ...@@ -713,7 +733,7 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
break; break;
case 18: case 18:
pr_debug("18bit\n"); dev_dbg(codec->dev, "18bit\n");
switch (sta32x->format) { switch (sta32x->format) {
case SND_SOC_DAIFMT_I2S: case SND_SOC_DAIFMT_I2S:
confb |= 0x8; confb |= 0x8;
...@@ -728,7 +748,7 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream, ...@@ -728,7 +748,7 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
break; break;
case 16: case 16:
pr_debug("16bit\n"); dev_dbg(codec->dev, "16bit\n");
switch (sta32x->format) { switch (sta32x->format) {
case SND_SOC_DAIFMT_I2S: case SND_SOC_DAIFMT_I2S:
confb |= 0x0; confb |= 0x0;
...@@ -746,8 +766,30 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream, ...@@ -746,8 +766,30 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
return -EINVAL; return -EINVAL;
} }
snd_soc_write(codec, STA32X_CONFA, confa); ret = regmap_update_bits(sta32x->regmap, STA32X_CONFA,
snd_soc_write(codec, STA32X_CONFB, confb); STA32X_CONFA_MCS_MASK | STA32X_CONFA_IR_MASK,
confa);
if (ret < 0)
return ret;
ret = regmap_update_bits(sta32x->regmap, STA32X_CONFB,
STA32X_CONFB_SAI_MASK | STA32X_CONFB_SAIFB,
confb);
if (ret < 0)
return ret;
return 0;
}
static int sta32x_startup_sequence(struct sta32x_priv *sta32x)
{
if (sta32x->gpiod_nreset) {
gpiod_set_value(sta32x->gpiod_nreset, 0);
mdelay(1);
gpiod_set_value(sta32x->gpiod_nreset, 1);
mdelay(1);
}
return 0; return 0;
} }
...@@ -766,14 +808,14 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec, ...@@ -766,14 +808,14 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec,
int ret; int ret;
struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
pr_debug("level = %d\n", level); dev_dbg(codec->dev, "level = %d\n", level);
switch (level) { switch (level) {
case SND_SOC_BIAS_ON: case SND_SOC_BIAS_ON:
break; break;
case SND_SOC_BIAS_PREPARE: case SND_SOC_BIAS_PREPARE:
/* Full power on */ /* Full power on */
snd_soc_update_bits(codec, STA32X_CONFF, regmap_update_bits(sta32x->regmap, STA32X_CONFF,
STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
STA32X_CONFF_PWDN | STA32X_CONFF_EAPD); STA32X_CONFF_PWDN | STA32X_CONFF_EAPD);
break; break;
...@@ -788,25 +830,28 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec, ...@@ -788,25 +830,28 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec,
return ret; return ret;
} }
sta32x_startup_sequence(sta32x);
sta32x_cache_sync(codec); sta32x_cache_sync(codec);
sta32x_watchdog_start(sta32x); sta32x_watchdog_start(sta32x);
} }
/* Power up to mute */ /* Power down */
/* FIXME */ regmap_update_bits(sta32x->regmap, STA32X_CONFF,
snd_soc_update_bits(codec, STA32X_CONFF, STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, 0);
STA32X_CONFF_PWDN | STA32X_CONFF_EAPD);
break; break;
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
/* The chip runs through the power down sequence for us. */ /* The chip runs through the power down sequence for us. */
snd_soc_update_bits(codec, STA32X_CONFF, regmap_update_bits(sta32x->regmap, STA32X_CONFF,
STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, 0);
STA32X_CONFF_PWDN);
msleep(300); msleep(300);
sta32x_watchdog_stop(sta32x); sta32x_watchdog_stop(sta32x);
if (sta32x->gpiod_nreset)
gpiod_set_value(sta32x->gpiod_nreset, 0);
regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies),
sta32x->supplies); sta32x->supplies);
break; break;
...@@ -822,7 +867,7 @@ static const struct snd_soc_dai_ops sta32x_dai_ops = { ...@@ -822,7 +867,7 @@ static const struct snd_soc_dai_ops sta32x_dai_ops = {
}; };
static struct snd_soc_dai_driver sta32x_dai = { static struct snd_soc_dai_driver sta32x_dai = {
.name = "STA32X", .name = "sta32x-hifi",
.playback = { .playback = {
.stream_name = "Playback", .stream_name = "Playback",
.channels_min = 2, .channels_min = 2,
...@@ -836,11 +881,8 @@ static struct snd_soc_dai_driver sta32x_dai = { ...@@ -836,11 +881,8 @@ static struct snd_soc_dai_driver sta32x_dai = {
static int sta32x_probe(struct snd_soc_codec *codec) static int sta32x_probe(struct snd_soc_codec *codec)
{ {
struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
struct sta32x_platform_data *pdata = sta32x->pdata;
int i, ret = 0, thermal = 0; int i, ret = 0, thermal = 0;
sta32x->codec = codec;
sta32x->pdata = dev_get_platdata(codec->dev);
ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies), ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
sta32x->supplies); sta32x->supplies);
if (ret != 0) { if (ret != 0) {
...@@ -848,50 +890,73 @@ static int sta32x_probe(struct snd_soc_codec *codec) ...@@ -848,50 +890,73 @@ static int sta32x_probe(struct snd_soc_codec *codec)
return ret; return ret;
} }
/* Chip documentation explicitly requires that the reset values ret = sta32x_startup_sequence(sta32x);
* of reserved register bits are left untouched. if (ret < 0) {
* Write the register default value to cache for reserved registers, dev_err(codec->dev, "Failed to startup device\n");
* so the write to the these registers are suppressed by the cache return ret;
* restore code when it skips writes of default registers. }
*/
regcache_cache_only(sta32x->regmap, true); /* CONFA */
snd_soc_write(codec, STA32X_CONFC, 0xc2); if (!pdata->thermal_warning_recovery)
snd_soc_write(codec, STA32X_CONFE, 0xc2);
snd_soc_write(codec, STA32X_CONFF, 0x5c);
snd_soc_write(codec, STA32X_MMUTE, 0x10);
snd_soc_write(codec, STA32X_AUTO1, 0x60);
snd_soc_write(codec, STA32X_AUTO3, 0x00);
snd_soc_write(codec, STA32X_C3CFG, 0x40);
regcache_cache_only(sta32x->regmap, false);
/* set thermal warning adjustment and recovery */
if (!(sta32x->pdata->thermal_conf & STA32X_THERMAL_ADJUSTMENT_ENABLE))
thermal |= STA32X_CONFA_TWAB; thermal |= STA32X_CONFA_TWAB;
if (!(sta32x->pdata->thermal_conf & STA32X_THERMAL_RECOVERY_ENABLE)) if (!pdata->thermal_warning_adjustment)
thermal |= STA32X_CONFA_TWRB; thermal |= STA32X_CONFA_TWRB;
snd_soc_update_bits(codec, STA32X_CONFA, if (!pdata->fault_detect_recovery)
STA32X_CONFA_TWAB | STA32X_CONFA_TWRB, thermal |= STA32X_CONFA_FDRB;
thermal); regmap_update_bits(sta32x->regmap, STA32X_CONFA,
STA32X_CONFA_TWAB | STA32X_CONFA_TWRB |
STA32X_CONFA_FDRB,
thermal);
/* CONFC */
regmap_update_bits(sta32x->regmap, STA32X_CONFC,
STA32X_CONFC_CSZ_MASK,
pdata->drop_compensation_ns
<< STA32X_CONFC_CSZ_SHIFT);
/* CONFE */
regmap_update_bits(sta32x->regmap, STA32X_CONFE,
STA32X_CONFE_MPCV,
pdata->max_power_use_mpcc ?
STA32X_CONFE_MPCV : 0);
regmap_update_bits(sta32x->regmap, STA32X_CONFE,
STA32X_CONFE_MPC,
pdata->max_power_correction ?
STA32X_CONFE_MPC : 0);
regmap_update_bits(sta32x->regmap, STA32X_CONFE,
STA32X_CONFE_AME,
pdata->am_reduction_mode ?
STA32X_CONFE_AME : 0);
regmap_update_bits(sta32x->regmap, STA32X_CONFE,
STA32X_CONFE_PWMS,
pdata->odd_pwm_speed_mode ?
STA32X_CONFE_PWMS : 0);
/* CONFF */
regmap_update_bits(sta32x->regmap, STA32X_CONFF,
STA32X_CONFF_IDE,
pdata->invalid_input_detect_mute ?
STA32X_CONFF_IDE : 0);
/* select output configuration */ /* select output configuration */
snd_soc_update_bits(codec, STA32X_CONFF, regmap_update_bits(sta32x->regmap, STA32X_CONFF,
STA32X_CONFF_OCFG_MASK, STA32X_CONFF_OCFG_MASK,
sta32x->pdata->output_conf pdata->output_conf
<< STA32X_CONFF_OCFG_SHIFT); << STA32X_CONFF_OCFG_SHIFT);
/* channel to output mapping */ /* channel to output mapping */
snd_soc_update_bits(codec, STA32X_C1CFG, regmap_update_bits(sta32x->regmap, STA32X_C1CFG,
STA32X_CxCFG_OM_MASK, STA32X_CxCFG_OM_MASK,
sta32x->pdata->ch1_output_mapping pdata->ch1_output_mapping
<< STA32X_CxCFG_OM_SHIFT); << STA32X_CxCFG_OM_SHIFT);
snd_soc_update_bits(codec, STA32X_C2CFG, regmap_update_bits(sta32x->regmap, STA32X_C2CFG,
STA32X_CxCFG_OM_MASK, STA32X_CxCFG_OM_MASK,
sta32x->pdata->ch2_output_mapping pdata->ch2_output_mapping
<< STA32X_CxCFG_OM_SHIFT); << STA32X_CxCFG_OM_SHIFT);
snd_soc_update_bits(codec, STA32X_C3CFG, regmap_update_bits(sta32x->regmap, STA32X_C3CFG,
STA32X_CxCFG_OM_MASK, STA32X_CxCFG_OM_MASK,
sta32x->pdata->ch3_output_mapping pdata->ch3_output_mapping
<< STA32X_CxCFG_OM_SHIFT); << STA32X_CxCFG_OM_SHIFT);
/* initialize coefficient shadow RAM with reset values */ /* initialize coefficient shadow RAM with reset values */
for (i = 4; i <= 49; i += 5) for (i = 4; i <= 49; i += 5)
...@@ -924,16 +989,6 @@ static int sta32x_remove(struct snd_soc_codec *codec) ...@@ -924,16 +989,6 @@ static int sta32x_remove(struct snd_soc_codec *codec)
return 0; return 0;
} }
static bool sta32x_reg_is_volatile(struct device *dev, unsigned int reg)
{
switch (reg) {
case STA32X_CONFA ... STA32X_L2ATRT:
case STA32X_MPCC1 ... STA32X_FDRC2:
return 0;
}
return 1;
}
static const struct snd_soc_codec_driver sta32x_codec = { static const struct snd_soc_codec_driver sta32x_codec = {
.probe = sta32x_probe, .probe = sta32x_probe,
.remove = sta32x_remove, .remove = sta32x_remove,
...@@ -954,12 +1009,75 @@ static const struct regmap_config sta32x_regmap = { ...@@ -954,12 +1009,75 @@ static const struct regmap_config sta32x_regmap = {
.reg_defaults = sta32x_regs, .reg_defaults = sta32x_regs,
.num_reg_defaults = ARRAY_SIZE(sta32x_regs), .num_reg_defaults = ARRAY_SIZE(sta32x_regs),
.cache_type = REGCACHE_RBTREE, .cache_type = REGCACHE_RBTREE,
.volatile_reg = sta32x_reg_is_volatile, .wr_table = &sta32x_write_regs,
.rd_table = &sta32x_read_regs,
.volatile_table = &sta32x_volatile_regs,
}; };
#ifdef CONFIG_OF
static const struct of_device_id st32x_dt_ids[] = {
{ .compatible = "st,sta32x", },
{ }
};
MODULE_DEVICE_TABLE(of, st32x_dt_ids);
static int sta32x_probe_dt(struct device *dev, struct sta32x_priv *sta32x)
{
struct device_node *np = dev->of_node;
struct sta32x_platform_data *pdata;
u16 tmp;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
of_property_read_u8(np, "st,output-conf",
&pdata->output_conf);
of_property_read_u8(np, "st,ch1-output-mapping",
&pdata->ch1_output_mapping);
of_property_read_u8(np, "st,ch2-output-mapping",
&pdata->ch2_output_mapping);
of_property_read_u8(np, "st,ch3-output-mapping",
&pdata->ch3_output_mapping);
if (of_get_property(np, "st,thermal-warning-recovery", NULL))
pdata->thermal_warning_recovery = 1;
if (of_get_property(np, "st,thermal-warning-adjustment", NULL))
pdata->thermal_warning_adjustment = 1;
if (of_get_property(np, "st,needs_esd_watchdog", NULL))
pdata->needs_esd_watchdog = 1;
tmp = 140;
of_property_read_u16(np, "st,drop-compensation-ns", &tmp);
pdata->drop_compensation_ns = clamp_t(u16, tmp, 0, 300) / 20;
/* CONFE */
if (of_get_property(np, "st,max-power-use-mpcc", NULL))
pdata->max_power_use_mpcc = 1;
if (of_get_property(np, "st,max-power-correction", NULL))
pdata->max_power_correction = 1;
if (of_get_property(np, "st,am-reduction-mode", NULL))
pdata->am_reduction_mode = 1;
if (of_get_property(np, "st,odd-pwm-speed-mode", NULL))
pdata->odd_pwm_speed_mode = 1;
/* CONFF */
if (of_get_property(np, "st,invalid-input-detect-mute", NULL))
pdata->invalid_input_detect_mute = 1;
sta32x->pdata = pdata;
return 0;
}
#endif
static int sta32x_i2c_probe(struct i2c_client *i2c, static int sta32x_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
struct device *dev = &i2c->dev;
struct sta32x_priv *sta32x; struct sta32x_priv *sta32x;
int ret, i; int ret, i;
...@@ -968,6 +1086,29 @@ static int sta32x_i2c_probe(struct i2c_client *i2c, ...@@ -968,6 +1086,29 @@ static int sta32x_i2c_probe(struct i2c_client *i2c,
if (!sta32x) if (!sta32x)
return -ENOMEM; return -ENOMEM;
mutex_init(&sta32x->coeff_lock);
sta32x->pdata = dev_get_platdata(dev);
#ifdef CONFIG_OF
if (dev->of_node) {
ret = sta32x_probe_dt(dev, sta32x);
if (ret < 0)
return ret;
}
#endif
/* GPIOs */
sta32x->gpiod_nreset = devm_gpiod_get(dev, "reset");
if (IS_ERR(sta32x->gpiod_nreset)) {
ret = PTR_ERR(sta32x->gpiod_nreset);
if (ret != -ENOENT && ret != -ENOSYS)
return ret;
sta32x->gpiod_nreset = NULL;
} else {
gpiod_direction_output(sta32x->gpiod_nreset, 0);
}
/* regulators */ /* regulators */
for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++) for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++)
sta32x->supplies[i].supply = sta32x_supply_names[i]; sta32x->supplies[i].supply = sta32x_supply_names[i];
...@@ -982,15 +1123,15 @@ static int sta32x_i2c_probe(struct i2c_client *i2c, ...@@ -982,15 +1123,15 @@ static int sta32x_i2c_probe(struct i2c_client *i2c,
sta32x->regmap = devm_regmap_init_i2c(i2c, &sta32x_regmap); sta32x->regmap = devm_regmap_init_i2c(i2c, &sta32x_regmap);
if (IS_ERR(sta32x->regmap)) { if (IS_ERR(sta32x->regmap)) {
ret = PTR_ERR(sta32x->regmap); ret = PTR_ERR(sta32x->regmap);
dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret); dev_err(dev, "Failed to init regmap: %d\n", ret);
return ret; return ret;
} }
i2c_set_clientdata(i2c, sta32x); i2c_set_clientdata(i2c, sta32x);
ret = snd_soc_register_codec(&i2c->dev, &sta32x_codec, &sta32x_dai, 1); ret = snd_soc_register_codec(dev, &sta32x_codec, &sta32x_dai, 1);
if (ret != 0) if (ret < 0)
dev_err(&i2c->dev, "Failed to register codec (%d)\n", ret); dev_err(dev, "Failed to register codec (%d)\n", ret);
return ret; return ret;
} }
...@@ -1013,6 +1154,7 @@ static struct i2c_driver sta32x_i2c_driver = { ...@@ -1013,6 +1154,7 @@ static struct i2c_driver sta32x_i2c_driver = {
.driver = { .driver = {
.name = "sta32x", .name = "sta32x",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = of_match_ptr(st32x_dt_ids),
}, },
.probe = sta32x_i2c_probe, .probe = sta32x_i2c_probe,
.remove = sta32x_i2c_remove, .remove = sta32x_i2c_remove,
......
...@@ -39,6 +39,37 @@ struct simple_card_data { ...@@ -39,6 +39,37 @@ struct simple_card_data {
#define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + i) #define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + i)
#define simple_priv_to_props(priv, i) ((priv)->dai_props + i) #define simple_priv_to_props(priv, i) ((priv)->dai_props + i)
static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct simple_dai_props *dai_props =
&priv->dai_props[rtd - rtd->card->rtd];
int ret;
ret = clk_prepare_enable(dai_props->cpu_dai.clk);
if (ret)
return ret;
ret = clk_prepare_enable(dai_props->codec_dai.clk);
if (ret)
clk_disable_unprepare(dai_props->cpu_dai.clk);
return ret;
}
static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct simple_dai_props *dai_props =
&priv->dai_props[rtd - rtd->card->rtd];
clk_disable_unprepare(dai_props->cpu_dai.clk);
clk_disable_unprepare(dai_props->codec_dai.clk);
}
static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params) struct snd_pcm_hw_params *params)
{ {
...@@ -58,6 +89,8 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, ...@@ -58,6 +89,8 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
} }
static struct snd_soc_ops asoc_simple_card_ops = { static struct snd_soc_ops asoc_simple_card_ops = {
.startup = asoc_simple_card_startup,
.shutdown = asoc_simple_card_shutdown,
.hw_params = asoc_simple_card_hw_params, .hw_params = asoc_simple_card_hw_params,
}; };
...@@ -219,6 +252,7 @@ asoc_simple_card_sub_parse_of(struct device_node *np, ...@@ -219,6 +252,7 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
} }
dai->sysclk = clk_get_rate(clk); dai->sysclk = clk_get_rate(clk);
dai->clk = clk;
} else if (!of_property_read_u32(np, "system-clock-frequency", &val)) { } else if (!of_property_read_u32(np, "system-clock-frequency", &val)) {
dai->sysclk = val; dai->sysclk = val;
} else { } else {
......
...@@ -250,14 +250,14 @@ static const struct snd_soc_dapm_route audio_map[] = { ...@@ -250,14 +250,14 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"FM Transmitter", NULL, "LLOUT"}, {"FM Transmitter", NULL, "LLOUT"},
{"FM Transmitter", NULL, "RLOUT"}, {"FM Transmitter", NULL, "RLOUT"},
{"DMic Rate 64", NULL, "Mic Bias"}, {"DMic Rate 64", NULL, "DMic"},
{"Mic Bias", NULL, "DMic"}, {"DMic", NULL, "Mic Bias"},
{"b LINE2R", NULL, "MONO_LOUT"}, {"b LINE2R", NULL, "MONO_LOUT"},
{"Earphone", NULL, "b HPLOUT"}, {"Earphone", NULL, "b HPLOUT"},
{"LINE1L", NULL, "b Mic Bias"}, {"LINE1L", NULL, "HS Mic"},
{"b Mic Bias", NULL, "HS Mic"} {"HS Mic", NULL, "b Mic Bias"},
}; };
static const char * const spk_function[] = {"Off", "On"}; static const char * const spk_function[] = {"Off", "On"};
......
...@@ -54,7 +54,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750 ...@@ -54,7 +54,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750
config SND_SOC_SAMSUNG_SMDK_WM8580 config SND_SOC_SAMSUNG_SMDK_WM8580
tristate "SoC I2S Audio support for WM8580 on SMDK" tristate "SoC I2S Audio support for WM8580 on SMDK"
depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110) depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110)
depends on REGMAP_I2C depends on I2C
select SND_SOC_WM8580 select SND_SOC_WM8580
select SND_SAMSUNG_I2S select SND_SAMSUNG_I2S
help help
...@@ -167,7 +167,7 @@ config SND_SOC_SAMSUNG_SMDK_SPDIF ...@@ -167,7 +167,7 @@ config SND_SOC_SAMSUNG_SMDK_SPDIF
config SND_SOC_SMDK_WM8580_PCM config SND_SOC_SMDK_WM8580_PCM
tristate "SoC PCM Audio support for WM8580 on SMDK" tristate "SoC PCM Audio support for WM8580 on SMDK"
depends on SND_SOC_SAMSUNG && (MACH_SMDKV210 || MACH_SMDKC110) depends on SND_SOC_SAMSUNG && (MACH_SMDKV210 || MACH_SMDKC110)
depends on REGMAP_I2C depends on I2C
select SND_SOC_WM8580 select SND_SOC_WM8580
select SND_SAMSUNG_PCM select SND_SAMSUNG_PCM
help help
......
...@@ -135,7 +135,6 @@ MODULE_DEVICE_TABLE(of, samsung_arndale_rt5631_of_match); ...@@ -135,7 +135,6 @@ MODULE_DEVICE_TABLE(of, samsung_arndale_rt5631_of_match);
static struct platform_driver arndale_audio_driver = { static struct platform_driver arndale_audio_driver = {
.driver = { .driver = {
.name = "arndale-audio", .name = "arndale-audio",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops, .pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(samsung_arndale_rt5631_of_match), .of_match_table = of_match_ptr(samsung_arndale_rt5631_of_match),
}, },
......
...@@ -10,9 +10,11 @@ ...@@ -10,9 +10,11 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <dt-bindings/sound/samsung-i2s.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
...@@ -59,10 +61,8 @@ struct samsung_i2s_dai_data { ...@@ -59,10 +61,8 @@ struct samsung_i2s_dai_data {
struct i2s_dai { struct i2s_dai {
/* Platform device for this DAI */ /* Platform device for this DAI */
struct platform_device *pdev; struct platform_device *pdev;
/* IOREMAP'd SFRs */ /* Memory mapped SFR region */
void __iomem *addr; void __iomem *addr;
/* Physical base address of SFRs */
u32 base;
/* Rate of RCLK source clock */ /* Rate of RCLK source clock */
unsigned long rclk_srcrate; unsigned long rclk_srcrate;
/* Frame Clock */ /* Frame Clock */
...@@ -83,8 +83,6 @@ struct i2s_dai { ...@@ -83,8 +83,6 @@ struct i2s_dai {
#define DAI_OPENED (1 << 0) /* Dai is opened */ #define DAI_OPENED (1 << 0) /* Dai is opened */
#define DAI_MANAGER (1 << 1) /* Dai is the manager */ #define DAI_MANAGER (1 << 1) /* Dai is the manager */
unsigned mode; unsigned mode;
/* CDCLK pin direction: 0 - input, 1 - output */
unsigned int cdclk_out:1;
/* Driver for this DAI */ /* Driver for this DAI */
struct snd_soc_dai_driver i2s_dai_drv; struct snd_soc_dai_driver i2s_dai_drv;
/* DMA parameters */ /* DMA parameters */
...@@ -95,8 +93,15 @@ struct i2s_dai { ...@@ -95,8 +93,15 @@ struct i2s_dai {
u32 suspend_i2smod; u32 suspend_i2smod;
u32 suspend_i2scon; u32 suspend_i2scon;
u32 suspend_i2spsr; u32 suspend_i2spsr;
unsigned long gpios[7]; /* i2s gpio line numbers */
const struct samsung_i2s_variant_regs *variant_regs; const struct samsung_i2s_variant_regs *variant_regs;
/* Spinlock protecting access to the device's registers */
spinlock_t spinlock;
spinlock_t *lock;
/* Below fields are only valid if this is the primary FIFO */
struct clk *clk_table[3];
struct clk_onecell_data clk_data;
}; };
/* Lock for cross i/f checks */ /* Lock for cross i/f checks */
...@@ -133,10 +138,16 @@ static inline bool tx_active(struct i2s_dai *i2s) ...@@ -133,10 +138,16 @@ static inline bool tx_active(struct i2s_dai *i2s)
return active ? true : false; return active ? true : false;
} }
/* Return pointer to the other DAI */
static inline struct i2s_dai *get_other_dai(struct i2s_dai *i2s)
{
return i2s->pri_dai ? : i2s->sec_dai;
}
/* If the other interface of the controller is transmitting data */ /* If the other interface of the controller is transmitting data */
static inline bool other_tx_active(struct i2s_dai *i2s) static inline bool other_tx_active(struct i2s_dai *i2s)
{ {
struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; struct i2s_dai *other = get_other_dai(i2s);
return tx_active(other); return tx_active(other);
} }
...@@ -163,7 +174,7 @@ static inline bool rx_active(struct i2s_dai *i2s) ...@@ -163,7 +174,7 @@ static inline bool rx_active(struct i2s_dai *i2s)
/* If the other interface of the controller is receiving data */ /* If the other interface of the controller is receiving data */
static inline bool other_rx_active(struct i2s_dai *i2s) static inline bool other_rx_active(struct i2s_dai *i2s)
{ {
struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; struct i2s_dai *other = get_other_dai(i2s);
return rx_active(other); return rx_active(other);
} }
...@@ -464,18 +475,23 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, ...@@ -464,18 +475,23 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
int clk_id, unsigned int rfs, int dir) int clk_id, unsigned int rfs, int dir)
{ {
struct i2s_dai *i2s = to_info(dai); struct i2s_dai *i2s = to_info(dai);
struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; struct i2s_dai *other = get_other_dai(i2s);
u32 mod = readl(i2s->addr + I2SMOD);
const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs; const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs;
unsigned int cdcon_mask = 1 << i2s_regs->cdclkcon_off; unsigned int cdcon_mask = 1 << i2s_regs->cdclkcon_off;
unsigned int rsrc_mask = 1 << i2s_regs->rclksrc_off; unsigned int rsrc_mask = 1 << i2s_regs->rclksrc_off;
u32 mod, mask, val = 0;
spin_lock(i2s->lock);
mod = readl(i2s->addr + I2SMOD);
spin_unlock(i2s->lock);
switch (clk_id) { switch (clk_id) {
case SAMSUNG_I2S_OPCLK: case SAMSUNG_I2S_OPCLK:
mod &= ~MOD_OPCLK_MASK; mask = MOD_OPCLK_MASK;
mod |= dir; val = dir;
break; break;
case SAMSUNG_I2S_CDCLK: case SAMSUNG_I2S_CDCLK:
mask = 1 << i2s_regs->cdclkcon_off;
/* Shouldn't matter in GATING(CLOCK_IN) mode */ /* Shouldn't matter in GATING(CLOCK_IN) mode */
if (dir == SND_SOC_CLOCK_IN) if (dir == SND_SOC_CLOCK_IN)
rfs = 0; rfs = 0;
...@@ -492,15 +508,15 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, ...@@ -492,15 +508,15 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
} }
if (dir == SND_SOC_CLOCK_IN) if (dir == SND_SOC_CLOCK_IN)
mod |= 1 << i2s_regs->cdclkcon_off; val = 1 << i2s_regs->cdclkcon_off;
else
mod &= ~(1 << i2s_regs->cdclkcon_off);
i2s->rfs = rfs; i2s->rfs = rfs;
break; break;
case SAMSUNG_I2S_RCLKSRC_0: /* clock corrsponding to IISMOD[10] := 0 */ case SAMSUNG_I2S_RCLKSRC_0: /* clock corrsponding to IISMOD[10] := 0 */
case SAMSUNG_I2S_RCLKSRC_1: /* clock corrsponding to IISMOD[10] := 1 */ case SAMSUNG_I2S_RCLKSRC_1: /* clock corrsponding to IISMOD[10] := 1 */
mask = 1 << i2s_regs->rclksrc_off;
if ((i2s->quirks & QUIRK_NO_MUXPSR) if ((i2s->quirks & QUIRK_NO_MUXPSR)
|| (clk_id == SAMSUNG_I2S_RCLKSRC_0)) || (clk_id == SAMSUNG_I2S_RCLKSRC_0))
clk_id = 0; clk_id = 0;
...@@ -550,18 +566,19 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, ...@@ -550,18 +566,19 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
return 0; return 0;
} }
if (clk_id == 0) if (clk_id == 1)
mod &= ~(1 << i2s_regs->rclksrc_off); val = 1 << i2s_regs->rclksrc_off;
else
mod |= 1 << i2s_regs->rclksrc_off;
break; break;
default: default:
dev_err(&i2s->pdev->dev, "We don't serve that!\n"); dev_err(&i2s->pdev->dev, "We don't serve that!\n");
return -EINVAL; return -EINVAL;
} }
spin_lock(i2s->lock);
mod = readl(i2s->addr + I2SMOD);
mod = (mod & ~mask) | val;
writel(mod, i2s->addr + I2SMOD); writel(mod, i2s->addr + I2SMOD);
spin_unlock(i2s->lock);
return 0; return 0;
} }
...@@ -570,9 +587,8 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, ...@@ -570,9 +587,8 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
unsigned int fmt) unsigned int fmt)
{ {
struct i2s_dai *i2s = to_info(dai); struct i2s_dai *i2s = to_info(dai);
u32 mod = readl(i2s->addr + I2SMOD);
int lrp_shift, sdf_shift, sdf_mask, lrp_rlow, mod_slave; int lrp_shift, sdf_shift, sdf_mask, lrp_rlow, mod_slave;
u32 tmp = 0; u32 mod, tmp = 0;
lrp_shift = i2s->variant_regs->lrp_off; lrp_shift = i2s->variant_regs->lrp_off;
sdf_shift = i2s->variant_regs->sdf_off; sdf_shift = i2s->variant_regs->sdf_off;
...@@ -632,12 +648,15 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, ...@@ -632,12 +648,15 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
return -EINVAL; return -EINVAL;
} }
spin_lock(i2s->lock);
mod = readl(i2s->addr + I2SMOD);
/* /*
* Don't change the I2S mode if any controller is active on this * Don't change the I2S mode if any controller is active on this
* channel. * channel.
*/ */
if (any_active(i2s) && if (any_active(i2s) &&
((mod & (sdf_mask | lrp_rlow | mod_slave)) != tmp)) { ((mod & (sdf_mask | lrp_rlow | mod_slave)) != tmp)) {
spin_unlock(i2s->lock);
dev_err(&i2s->pdev->dev, dev_err(&i2s->pdev->dev,
"%s:%d Other DAI busy\n", __func__, __LINE__); "%s:%d Other DAI busy\n", __func__, __LINE__);
return -EAGAIN; return -EAGAIN;
...@@ -646,6 +665,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, ...@@ -646,6 +665,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
mod &= ~(sdf_mask | lrp_rlow | mod_slave); mod &= ~(sdf_mask | lrp_rlow | mod_slave);
mod |= tmp; mod |= tmp;
writel(mod, i2s->addr + I2SMOD); writel(mod, i2s->addr + I2SMOD);
spin_unlock(i2s->lock);
return 0; return 0;
} }
...@@ -654,16 +674,16 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, ...@@ -654,16 +674,16 @@ static int i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{ {
struct i2s_dai *i2s = to_info(dai); struct i2s_dai *i2s = to_info(dai);
u32 mod = readl(i2s->addr + I2SMOD); u32 mod, mask = 0, val = 0;
if (!is_secondary(i2s)) if (!is_secondary(i2s))
mod &= ~(MOD_DC2_EN | MOD_DC1_EN); mask |= (MOD_DC2_EN | MOD_DC1_EN);
switch (params_channels(params)) { switch (params_channels(params)) {
case 6: case 6:
mod |= MOD_DC2_EN; val |= MOD_DC2_EN;
case 4: case 4:
mod |= MOD_DC1_EN; val |= MOD_DC1_EN;
break; break;
case 2: case 2:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
...@@ -685,44 +705,49 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, ...@@ -685,44 +705,49 @@ static int i2s_hw_params(struct snd_pcm_substream *substream,
} }
if (is_secondary(i2s)) if (is_secondary(i2s))
mod &= ~MOD_BLCS_MASK; mask |= MOD_BLCS_MASK;
else else
mod &= ~MOD_BLCP_MASK; mask |= MOD_BLCP_MASK;
if (is_manager(i2s)) if (is_manager(i2s))
mod &= ~MOD_BLC_MASK; mask |= MOD_BLC_MASK;
switch (params_width(params)) { switch (params_width(params)) {
case 8: case 8:
if (is_secondary(i2s)) if (is_secondary(i2s))
mod |= MOD_BLCS_8BIT; val |= MOD_BLCS_8BIT;
else else
mod |= MOD_BLCP_8BIT; val |= MOD_BLCP_8BIT;
if (is_manager(i2s)) if (is_manager(i2s))
mod |= MOD_BLC_8BIT; val |= MOD_BLC_8BIT;
break; break;
case 16: case 16:
if (is_secondary(i2s)) if (is_secondary(i2s))
mod |= MOD_BLCS_16BIT; val |= MOD_BLCS_16BIT;
else else
mod |= MOD_BLCP_16BIT; val |= MOD_BLCP_16BIT;
if (is_manager(i2s)) if (is_manager(i2s))
mod |= MOD_BLC_16BIT; val |= MOD_BLC_16BIT;
break; break;
case 24: case 24:
if (is_secondary(i2s)) if (is_secondary(i2s))
mod |= MOD_BLCS_24BIT; val |= MOD_BLCS_24BIT;
else else
mod |= MOD_BLCP_24BIT; val |= MOD_BLCP_24BIT;
if (is_manager(i2s)) if (is_manager(i2s))
mod |= MOD_BLC_24BIT; val |= MOD_BLC_24BIT;
break; break;
default: default:
dev_err(&i2s->pdev->dev, "Format(%d) not supported\n", dev_err(&i2s->pdev->dev, "Format(%d) not supported\n",
params_format(params)); params_format(params));
return -EINVAL; return -EINVAL;
} }
spin_lock(i2s->lock);
mod = readl(i2s->addr + I2SMOD);
mod = (mod & ~mask) | val;
writel(mod, i2s->addr + I2SMOD); writel(mod, i2s->addr + I2SMOD);
spin_unlock(i2s->lock);
samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture);
...@@ -736,7 +761,7 @@ static int i2s_startup(struct snd_pcm_substream *substream, ...@@ -736,7 +761,7 @@ static int i2s_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
struct i2s_dai *i2s = to_info(dai); struct i2s_dai *i2s = to_info(dai);
struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; struct i2s_dai *other = get_other_dai(i2s);
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&lock, flags); spin_lock_irqsave(&lock, flags);
...@@ -753,9 +778,6 @@ static int i2s_startup(struct snd_pcm_substream *substream, ...@@ -753,9 +778,6 @@ static int i2s_startup(struct snd_pcm_substream *substream,
spin_unlock_irqrestore(&lock, flags); spin_unlock_irqrestore(&lock, flags);
if (!is_opened(other) && i2s->cdclk_out)
i2s_set_sysclk(dai, SAMSUNG_I2S_CDCLK,
0, SND_SOC_CLOCK_OUT);
return 0; return 0;
} }
...@@ -763,38 +785,27 @@ static void i2s_shutdown(struct snd_pcm_substream *substream, ...@@ -763,38 +785,27 @@ static void i2s_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
struct i2s_dai *i2s = to_info(dai); struct i2s_dai *i2s = to_info(dai);
struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; struct i2s_dai *other = get_other_dai(i2s);
unsigned long flags; unsigned long flags;
const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs;
spin_lock_irqsave(&lock, flags); spin_lock_irqsave(&lock, flags);
i2s->mode &= ~DAI_OPENED; i2s->mode &= ~DAI_OPENED;
i2s->mode &= ~DAI_MANAGER; i2s->mode &= ~DAI_MANAGER;
if (is_opened(other)) { if (is_opened(other))
other->mode |= DAI_MANAGER; other->mode |= DAI_MANAGER;
} else {
u32 mod = readl(i2s->addr + I2SMOD);
i2s->cdclk_out = !(mod & (1 << i2s_regs->cdclkcon_off));
if (other)
other->cdclk_out = i2s->cdclk_out;
}
/* Reset any constraint on RFS and BFS */ /* Reset any constraint on RFS and BFS */
i2s->rfs = 0; i2s->rfs = 0;
i2s->bfs = 0; i2s->bfs = 0;
spin_unlock_irqrestore(&lock, flags); spin_unlock_irqrestore(&lock, flags);
/* Gate CDCLK by default */
if (!is_opened(other))
i2s_set_sysclk(dai, SAMSUNG_I2S_CDCLK,
0, SND_SOC_CLOCK_IN);
} }
static int config_setup(struct i2s_dai *i2s) static int config_setup(struct i2s_dai *i2s)
{ {
struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; struct i2s_dai *other = get_other_dai(i2s);
unsigned rfs, bfs, blc; unsigned rfs, bfs, blc;
u32 psr; u32 psr;
...@@ -864,10 +875,10 @@ static int i2s_trigger(struct snd_pcm_substream *substream, ...@@ -864,10 +875,10 @@ static int i2s_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
local_irq_save(flags); spin_lock_irqsave(i2s->lock, flags);
if (config_setup(i2s)) { if (config_setup(i2s)) {
local_irq_restore(flags); spin_unlock_irqrestore(i2s->lock, flags);
return -EINVAL; return -EINVAL;
} }
...@@ -876,12 +887,12 @@ static int i2s_trigger(struct snd_pcm_substream *substream, ...@@ -876,12 +887,12 @@ static int i2s_trigger(struct snd_pcm_substream *substream,
else else
i2s_txctrl(i2s, 1); i2s_txctrl(i2s, 1);
local_irq_restore(flags); spin_unlock_irqrestore(i2s->lock, flags);
break; break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
local_irq_save(flags); spin_lock_irqsave(i2s->lock, flags);
if (capture) { if (capture) {
i2s_rxctrl(i2s, 0); i2s_rxctrl(i2s, 0);
...@@ -891,7 +902,7 @@ static int i2s_trigger(struct snd_pcm_substream *substream, ...@@ -891,7 +902,7 @@ static int i2s_trigger(struct snd_pcm_substream *substream,
i2s_fifo(i2s, FIC_TXFLUSH); i2s_fifo(i2s, FIC_TXFLUSH);
} }
local_irq_restore(flags); spin_unlock_irqrestore(i2s->lock, flags);
break; break;
} }
...@@ -902,7 +913,7 @@ static int i2s_set_clkdiv(struct snd_soc_dai *dai, ...@@ -902,7 +913,7 @@ static int i2s_set_clkdiv(struct snd_soc_dai *dai,
int div_id, int div) int div_id, int div)
{ {
struct i2s_dai *i2s = to_info(dai); struct i2s_dai *i2s = to_info(dai);
struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; struct i2s_dai *other = get_other_dai(i2s);
switch (div_id) { switch (div_id) {
case SAMSUNG_I2S_DIV_BCLK: case SAMSUNG_I2S_DIV_BCLK:
...@@ -971,58 +982,36 @@ static int i2s_resume(struct snd_soc_dai *dai) ...@@ -971,58 +982,36 @@ static int i2s_resume(struct snd_soc_dai *dai)
static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
{ {
struct i2s_dai *i2s = to_info(dai); struct i2s_dai *i2s = to_info(dai);
struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; struct i2s_dai *other = get_other_dai(i2s);
int ret; unsigned long flags;
if (other && other->clk) { /* If this is probe on secondary */ if (is_secondary(i2s)) { /* If this is probe on the secondary DAI */
samsung_asoc_init_dma_data(dai, &other->sec_dai->dma_playback, samsung_asoc_init_dma_data(dai, &other->sec_dai->dma_playback,
NULL); NULL);
goto probe_exit; } else {
} samsung_asoc_init_dma_data(dai, &i2s->dma_playback,
&i2s->dma_capture);
i2s->addr = ioremap(i2s->base, 0x100);
if (i2s->addr == NULL) {
dev_err(&i2s->pdev->dev, "cannot ioremap registers\n");
return -ENXIO;
}
i2s->clk = clk_get(&i2s->pdev->dev, "iis");
if (IS_ERR(i2s->clk)) {
dev_err(&i2s->pdev->dev, "failed to get i2s_clock\n");
iounmap(i2s->addr);
return PTR_ERR(i2s->clk);
}
ret = clk_prepare_enable(i2s->clk);
if (ret != 0) {
dev_err(&i2s->pdev->dev, "failed to enable clock: %d\n", ret);
return ret;
}
samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture);
if (other) {
other->addr = i2s->addr;
other->clk = i2s->clk;
}
if (i2s->quirks & QUIRK_NEED_RSTCLR) if (i2s->quirks & QUIRK_NEED_RSTCLR)
writel(CON_RSTCLR, i2s->addr + I2SCON); writel(CON_RSTCLR, i2s->addr + I2SCON);
if (i2s->quirks & QUIRK_SUPPORTS_IDMA) if (i2s->quirks & QUIRK_SUPPORTS_IDMA)
idma_reg_addr_init(i2s->addr, idma_reg_addr_init(i2s->addr,
i2s->sec_dai->idma_playback.dma_addr); i2s->sec_dai->idma_playback.dma_addr);
}
probe_exit:
/* Reset any constraint on RFS and BFS */ /* Reset any constraint on RFS and BFS */
i2s->rfs = 0; i2s->rfs = 0;
i2s->bfs = 0; i2s->bfs = 0;
i2s->rclk_srcrate = 0; i2s->rclk_srcrate = 0;
spin_lock_irqsave(i2s->lock, flags);
i2s_txctrl(i2s, 0); i2s_txctrl(i2s, 0);
i2s_rxctrl(i2s, 0); i2s_rxctrl(i2s, 0);
i2s_fifo(i2s, FIC_TXFLUSH); i2s_fifo(i2s, FIC_TXFLUSH);
i2s_fifo(other, FIC_TXFLUSH); i2s_fifo(other, FIC_TXFLUSH);
i2s_fifo(i2s, FIC_RXFLUSH); i2s_fifo(i2s, FIC_RXFLUSH);
spin_unlock_irqrestore(i2s->lock, flags);
/* Gate CDCLK by default */ /* Gate CDCLK by default */
if (!is_opened(other)) if (!is_opened(other))
...@@ -1035,21 +1024,15 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) ...@@ -1035,21 +1024,15 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) static int samsung_i2s_dai_remove(struct snd_soc_dai *dai)
{ {
struct i2s_dai *i2s = snd_soc_dai_get_drvdata(dai); struct i2s_dai *i2s = snd_soc_dai_get_drvdata(dai);
struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
if (!other || !other->clk) {
if (i2s->quirks & QUIRK_NEED_RSTCLR) if (!is_secondary(i2s)) {
if (i2s->quirks & QUIRK_NEED_RSTCLR) {
spin_lock(i2s->lock);
writel(0, i2s->addr + I2SCON); writel(0, i2s->addr + I2SCON);
spin_unlock(i2s->lock);
clk_disable_unprepare(i2s->clk); }
clk_put(i2s->clk);
iounmap(i2s->addr);
} }
i2s->clk = NULL;
return 0; return 0;
} }
...@@ -1124,15 +1107,14 @@ static const struct of_device_id exynos_i2s_match[]; ...@@ -1124,15 +1107,14 @@ static const struct of_device_id exynos_i2s_match[];
static inline const struct samsung_i2s_dai_data *samsung_i2s_get_driver_data( static inline const struct samsung_i2s_dai_data *samsung_i2s_get_driver_data(
struct platform_device *pdev) struct platform_device *pdev)
{ {
#ifdef CONFIG_OF if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
if (pdev->dev.of_node) {
const struct of_device_id *match; const struct of_device_id *match;
match = of_match_node(exynos_i2s_match, pdev->dev.of_node); match = of_match_node(exynos_i2s_match, pdev->dev.of_node);
return match->data; return match ? match->data : NULL;
} else } else {
#endif
return (struct samsung_i2s_dai_data *) return (struct samsung_i2s_dai_data *)
platform_get_device_id(pdev)->driver_data; platform_get_device_id(pdev)->driver_data;
}
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
...@@ -1155,6 +1137,87 @@ static int i2s_runtime_resume(struct device *dev) ...@@ -1155,6 +1137,87 @@ static int i2s_runtime_resume(struct device *dev)
} }
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
static void i2s_unregister_clocks(struct i2s_dai *i2s)
{
int i;
for (i = 0; i < i2s->clk_data.clk_num; i++) {
if (!IS_ERR(i2s->clk_table[i]))
clk_unregister(i2s->clk_table[i]);
}
}
static void i2s_unregister_clock_provider(struct platform_device *pdev)
{
struct i2s_dai *i2s = dev_get_drvdata(&pdev->dev);
of_clk_del_provider(pdev->dev.of_node);
i2s_unregister_clocks(i2s);
}
static int i2s_register_clock_provider(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct i2s_dai *i2s = dev_get_drvdata(dev);
const char *clk_name[2] = { "i2s_opclk0", "i2s_opclk1" };
const char *p_names[2] = { NULL };
const struct samsung_i2s_variant_regs *reg_info = i2s->variant_regs;
struct clk *rclksrc;
int ret, i;
/* Register the clock provider only if it's expected in the DTB */
if (!of_find_property(dev->of_node, "#clock-cells", NULL))
return 0;
/* Get the RCLKSRC mux clock parent clock names */
for (i = 0; i < ARRAY_SIZE(p_names); i++) {
rclksrc = clk_get(dev, clk_name[i]);
if (IS_ERR(rclksrc))
continue;
p_names[i] = __clk_get_name(rclksrc);
clk_put(rclksrc);
}
if (!(i2s->quirks & QUIRK_NO_MUXPSR)) {
/* Activate the prescaler */
u32 val = readl(i2s->addr + I2SPSR);
writel(val | PSR_PSREN, i2s->addr + I2SPSR);
i2s->clk_table[CLK_I2S_RCLK_SRC] = clk_register_mux(NULL,
"i2s_rclksrc", p_names, ARRAY_SIZE(p_names),
CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
i2s->addr + I2SMOD, reg_info->rclksrc_off,
1, 0, i2s->lock);
i2s->clk_table[CLK_I2S_RCLK_PSR] = clk_register_divider(NULL,
"i2s_presc", "i2s_rclksrc",
CLK_SET_RATE_PARENT,
i2s->addr + I2SPSR, 8, 6, 0, i2s->lock);
p_names[0] = "i2s_presc";
i2s->clk_data.clk_num = 2;
}
of_property_read_string_index(dev->of_node,
"clock-output-names", 0, &clk_name[0]);
i2s->clk_table[CLK_I2S_CDCLK] = clk_register_gate(NULL, clk_name[0],
p_names[0], CLK_SET_RATE_PARENT,
i2s->addr + I2SMOD, reg_info->cdclkcon_off,
CLK_GATE_SET_TO_DISABLE, i2s->lock);
i2s->clk_data.clk_num += 1;
i2s->clk_data.clks = i2s->clk_table;
ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
&i2s->clk_data);
if (ret < 0) {
dev_err(dev, "failed to add clock provider: %d\n", ret);
i2s_unregister_clocks(i2s);
}
return ret;
}
static int samsung_i2s_probe(struct platform_device *pdev) static int samsung_i2s_probe(struct platform_device *pdev)
{ {
struct i2s_dai *pri_dai, *sec_dai = NULL; struct i2s_dai *pri_dai, *sec_dai = NULL;
...@@ -1164,7 +1227,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) ...@@ -1164,7 +1227,7 @@ static int samsung_i2s_probe(struct platform_device *pdev)
u32 regs_base, quirks = 0, idma_addr = 0; u32 regs_base, quirks = 0, idma_addr = 0;
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
const struct samsung_i2s_dai_data *i2s_dai_data; const struct samsung_i2s_dai_data *i2s_dai_data;
int ret = 0; int ret;
/* Call during Seconday interface registration */ /* Call during Seconday interface registration */
i2s_dai_data = samsung_i2s_get_driver_data(pdev); i2s_dai_data = samsung_i2s_get_driver_data(pdev);
...@@ -1175,11 +1238,13 @@ static int samsung_i2s_probe(struct platform_device *pdev) ...@@ -1175,11 +1238,13 @@ static int samsung_i2s_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Unable to get drvdata\n"); dev_err(&pdev->dev, "Unable to get drvdata\n");
return -EFAULT; return -EFAULT;
} }
devm_snd_soc_register_component(&sec_dai->pdev->dev, ret = devm_snd_soc_register_component(&sec_dai->pdev->dev,
&samsung_i2s_component, &samsung_i2s_component,
&sec_dai->i2s_dai_drv, 1); &sec_dai->i2s_dai_drv, 1);
samsung_asoc_dma_platform_register(&pdev->dev); if (ret != 0)
return 0; return ret;
return samsung_asoc_dma_platform_register(&pdev->dev);
} }
pri_dai = i2s_alloc_dai(pdev, false); pri_dai = i2s_alloc_dai(pdev, false);
...@@ -1188,6 +1253,9 @@ static int samsung_i2s_probe(struct platform_device *pdev) ...@@ -1188,6 +1253,9 @@ static int samsung_i2s_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
} }
spin_lock_init(&pri_dai->spinlock);
pri_dai->lock = &pri_dai->spinlock;
if (!np) { if (!np) {
res = platform_get_resource(pdev, IORESOURCE_DMA, 0); res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!res) { if (!res) {
...@@ -1229,25 +1297,29 @@ static int samsung_i2s_probe(struct platform_device *pdev) ...@@ -1229,25 +1297,29 @@ static int samsung_i2s_probe(struct platform_device *pdev)
} }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) { pri_dai->addr = devm_ioremap_resource(&pdev->dev, res);
dev_err(&pdev->dev, "Unable to get I2S SFR address\n"); if (IS_ERR(pri_dai->addr))
return -ENXIO; return PTR_ERR(pri_dai->addr);
}
if (!request_mem_region(res->start, resource_size(res),
"samsung-i2s")) {
dev_err(&pdev->dev, "Unable to request SFR region\n");
return -EBUSY;
}
regs_base = res->start; regs_base = res->start;
pri_dai->clk = devm_clk_get(&pdev->dev, "iis");
if (IS_ERR(pri_dai->clk)) {
dev_err(&pdev->dev, "Failed to get iis clock\n");
return PTR_ERR(pri_dai->clk);
}
ret = clk_prepare_enable(pri_dai->clk);
if (ret != 0) {
dev_err(&pdev->dev, "failed to enable clock: %d\n", ret);
return ret;
}
pri_dai->dma_playback.dma_addr = regs_base + I2STXD; pri_dai->dma_playback.dma_addr = regs_base + I2STXD;
pri_dai->dma_capture.dma_addr = regs_base + I2SRXD; pri_dai->dma_capture.dma_addr = regs_base + I2SRXD;
pri_dai->dma_playback.ch_name = "tx"; pri_dai->dma_playback.ch_name = "tx";
pri_dai->dma_capture.ch_name = "rx"; pri_dai->dma_capture.ch_name = "rx";
pri_dai->dma_playback.dma_size = 4; pri_dai->dma_playback.dma_size = 4;
pri_dai->dma_capture.dma_size = 4; pri_dai->dma_capture.dma_size = 4;
pri_dai->base = regs_base;
pri_dai->quirks = quirks; pri_dai->quirks = quirks;
pri_dai->variant_regs = i2s_dai_data->i2s_variant_regs; pri_dai->variant_regs = i2s_dai_data->i2s_variant_regs;
...@@ -1258,10 +1330,10 @@ static int samsung_i2s_probe(struct platform_device *pdev) ...@@ -1258,10 +1330,10 @@ static int samsung_i2s_probe(struct platform_device *pdev)
sec_dai = i2s_alloc_dai(pdev, true); sec_dai = i2s_alloc_dai(pdev, true);
if (!sec_dai) { if (!sec_dai) {
dev_err(&pdev->dev, "Unable to alloc I2S_sec\n"); dev_err(&pdev->dev, "Unable to alloc I2S_sec\n");
ret = -ENOMEM; return -ENOMEM;
goto err;
} }
sec_dai->lock = &pri_dai->spinlock;
sec_dai->variant_regs = pri_dai->variant_regs; sec_dai->variant_regs = pri_dai->variant_regs;
sec_dai->dma_playback.dma_addr = regs_base + I2STXDS; sec_dai->dma_playback.dma_addr = regs_base + I2STXDS;
sec_dai->dma_playback.ch_name = "tx-sec"; sec_dai->dma_playback.ch_name = "tx-sec";
...@@ -1273,7 +1345,8 @@ static int samsung_i2s_probe(struct platform_device *pdev) ...@@ -1273,7 +1345,8 @@ static int samsung_i2s_probe(struct platform_device *pdev)
} }
sec_dai->dma_playback.dma_size = 4; sec_dai->dma_playback.dma_size = 4;
sec_dai->base = regs_base; sec_dai->addr = pri_dai->addr;
sec_dai->clk = pri_dai->clk;
sec_dai->quirks = quirks; sec_dai->quirks = quirks;
sec_dai->idma_playback.dma_addr = idma_addr; sec_dai->idma_playback.dma_addr = idma_addr;
sec_dai->pri_dai = pri_dai; sec_dai->pri_dai = pri_dai;
...@@ -1282,8 +1355,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) ...@@ -1282,8 +1355,7 @@ static int samsung_i2s_probe(struct platform_device *pdev)
if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) { if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
dev_err(&pdev->dev, "Unable to configure gpio\n"); dev_err(&pdev->dev, "Unable to configure gpio\n");
ret = -EINVAL; return -EINVAL;
goto err;
} }
devm_snd_soc_register_component(&pri_dai->pdev->dev, devm_snd_soc_register_component(&pri_dai->pdev->dev,
...@@ -1292,32 +1364,30 @@ static int samsung_i2s_probe(struct platform_device *pdev) ...@@ -1292,32 +1364,30 @@ static int samsung_i2s_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
samsung_asoc_dma_platform_register(&pdev->dev); ret = samsung_asoc_dma_platform_register(&pdev->dev);
if (ret != 0)
return 0; return ret;
err:
if (res)
release_mem_region(regs_base, resource_size(res));
return ret; return i2s_register_clock_provider(pdev);
} }
static int samsung_i2s_remove(struct platform_device *pdev) static int samsung_i2s_remove(struct platform_device *pdev)
{ {
struct i2s_dai *i2s, *other; struct i2s_dai *i2s, *other;
struct resource *res;
i2s = dev_get_drvdata(&pdev->dev); i2s = dev_get_drvdata(&pdev->dev);
other = i2s->pri_dai ? : i2s->sec_dai; other = get_other_dai(i2s);
if (other) { if (other) {
other->pri_dai = NULL; other->pri_dai = NULL;
other->sec_dai = NULL; other->sec_dai = NULL;
} else { } else {
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); }
if (res)
release_mem_region(res->start, resource_size(res)); if (!is_secondary(i2s)) {
i2s_unregister_clock_provider(pdev);
clk_disable_unprepare(i2s->clk);
} }
i2s->pri_dai = NULL; i2s->pri_dai = NULL;
......
...@@ -83,22 +83,6 @@ static struct snd_soc_ops jive_ops = { ...@@ -83,22 +83,6 @@ static struct snd_soc_ops jive_ops = {
.hw_params = jive_hw_params, .hw_params = jive_hw_params,
}; };
static int jive_wm8750_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
/* These endpoints are not being used. */
snd_soc_dapm_nc_pin(dapm, "LINPUT2");
snd_soc_dapm_nc_pin(dapm, "RINPUT2");
snd_soc_dapm_nc_pin(dapm, "LINPUT3");
snd_soc_dapm_nc_pin(dapm, "RINPUT3");
snd_soc_dapm_nc_pin(dapm, "OUT3");
snd_soc_dapm_nc_pin(dapm, "MONO");
return 0;
}
static struct snd_soc_dai_link jive_dai = { static struct snd_soc_dai_link jive_dai = {
.name = "wm8750", .name = "wm8750",
.stream_name = "WM8750", .stream_name = "WM8750",
...@@ -106,7 +90,6 @@ static struct snd_soc_dai_link jive_dai = { ...@@ -106,7 +90,6 @@ static struct snd_soc_dai_link jive_dai = {
.codec_dai_name = "wm8750-hifi", .codec_dai_name = "wm8750-hifi",
.platform_name = "s3c2412-i2s", .platform_name = "s3c2412-i2s",
.codec_name = "wm8750.0-001a", .codec_name = "wm8750.0-001a",
.init = jive_wm8750_init,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAIFMT_CBS_CFS,
.ops = &jive_ops, .ops = &jive_ops,
...@@ -123,6 +106,7 @@ static struct snd_soc_card snd_soc_machine_jive = { ...@@ -123,6 +106,7 @@ static struct snd_soc_card snd_soc_machine_jive = {
.num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets), .num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets),
.dapm_routes = audio_map, .dapm_routes = audio_map,
.num_dapm_routes = ARRAY_SIZE(audio_map), .num_dapm_routes = ARRAY_SIZE(audio_map),
.fully_routed = true,
}; };
static struct platform_device *jive_snd_device; static struct platform_device *jive_snd_device;
......
...@@ -21,6 +21,8 @@ struct odroidx2_drv_data { ...@@ -21,6 +21,8 @@ struct odroidx2_drv_data {
/* The I2S CDCLK output clock frequency for the MAX98090 codec */ /* The I2S CDCLK output clock frequency for the MAX98090 codec */
#define MAX98090_MCLK 19200000 #define MAX98090_MCLK 19200000
static struct snd_soc_dai_link odroidx2_dai[];
static int odroidx2_late_probe(struct snd_soc_card *card) static int odroidx2_late_probe(struct snd_soc_card *card)
{ {
struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
...@@ -29,7 +31,9 @@ static int odroidx2_late_probe(struct snd_soc_card *card) ...@@ -29,7 +31,9 @@ static int odroidx2_late_probe(struct snd_soc_card *card)
ret = snd_soc_dai_set_sysclk(codec_dai, 0, MAX98090_MCLK, ret = snd_soc_dai_set_sysclk(codec_dai, 0, MAX98090_MCLK,
SND_SOC_CLOCK_IN); SND_SOC_CLOCK_IN);
if (ret < 0)
if (ret < 0 || of_find_property(odroidx2_dai[0].codec_of_node,
"clocks", NULL))
return ret; return ret;
/* Set the cpu DAI configuration in order to use CDCLK */ /* Set the cpu DAI configuration in order to use CDCLK */
......
...@@ -136,13 +136,10 @@ static const struct snd_soc_dapm_route smdk_wm8580_audio_map[] = { ...@@ -136,13 +136,10 @@ static const struct snd_soc_dapm_route smdk_wm8580_audio_map[] = {
static int smdk_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd) static int smdk_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd)
{ {
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
/* Enabling the microphone requires the fitting of a 0R /* Enabling the microphone requires the fitting of a 0R
* resistor to connect the line from the microphone jack. * resistor to connect the line from the microphone jack.
*/ */
snd_soc_dapm_disable_pin(dapm, "MicIn"); snd_soc_dapm_disable_pin(&rtd->card->dapm, "MicIn");
return 0; return 0;
} }
......
...@@ -305,11 +305,6 @@ static struct snd_pcm_ops camelot_pcm_ops = { ...@@ -305,11 +305,6 @@ static struct snd_pcm_ops camelot_pcm_ops = {
.pointer = camelot_pos, .pointer = camelot_pos,
}; };
static void camelot_pcm_free(struct snd_pcm *pcm)
{
snd_pcm_lib_preallocate_free_for_all(pcm);
}
static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd) static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd)
{ {
struct snd_pcm *pcm = rtd->pcm; struct snd_pcm *pcm = rtd->pcm;
...@@ -328,7 +323,6 @@ static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd) ...@@ -328,7 +323,6 @@ static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd)
static struct snd_soc_platform_driver sh7760_soc_platform = { static struct snd_soc_platform_driver sh7760_soc_platform = {
.ops = &camelot_pcm_ops, .ops = &camelot_pcm_ops,
.pcm_new = camelot_pcm_new, .pcm_new = camelot_pcm_new,
.pcm_free = camelot_pcm_free,
}; };
static int sh7760_soc_platform_probe(struct platform_device *pdev) static int sh7760_soc_platform_probe(struct platform_device *pdev)
......
...@@ -1762,11 +1762,6 @@ static struct snd_pcm_ops fsi_pcm_ops = { ...@@ -1762,11 +1762,6 @@ static struct snd_pcm_ops fsi_pcm_ops = {
#define PREALLOC_BUFFER (32 * 1024) #define PREALLOC_BUFFER (32 * 1024)
#define PREALLOC_BUFFER_MAX (32 * 1024) #define PREALLOC_BUFFER_MAX (32 * 1024)
static void fsi_pcm_free(struct snd_pcm *pcm)
{
snd_pcm_lib_preallocate_free_for_all(pcm);
}
static int fsi_pcm_new(struct snd_soc_pcm_runtime *rtd) static int fsi_pcm_new(struct snd_soc_pcm_runtime *rtd)
{ {
return snd_pcm_lib_preallocate_pages_for_all( return snd_pcm_lib_preallocate_pages_for_all(
...@@ -1818,7 +1813,6 @@ static struct snd_soc_dai_driver fsi_soc_dai[] = { ...@@ -1818,7 +1813,6 @@ static struct snd_soc_dai_driver fsi_soc_dai[] = {
static struct snd_soc_platform_driver fsi_soc_platform = { static struct snd_soc_platform_driver fsi_soc_platform = {
.ops = &fsi_pcm_ops, .ops = &fsi_pcm_ops,
.pcm_new = fsi_pcm_new, .pcm_new = fsi_pcm_new,
.pcm_free = fsi_pcm_free,
}; };
static const struct snd_soc_component_driver fsi_soc_component = { static const struct snd_soc_component_driver fsi_soc_component = {
......
...@@ -589,7 +589,6 @@ static void siu_pcm_free(struct snd_pcm *pcm) ...@@ -589,7 +589,6 @@ static void siu_pcm_free(struct snd_pcm *pcm)
tasklet_kill(&port_info->playback.tasklet); tasklet_kill(&port_info->playback.tasklet);
siu_free_port(port_info); siu_free_port(port_info);
snd_pcm_lib_preallocate_free_for_all(pcm);
dev_dbg(pcm->card->dev, "%s\n", __func__); dev_dbg(pcm->card->dev, "%s\n", __func__);
} }
......
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