From 6387f866a2ccbf393ed5ffe7e2754eb5d0781441 Mon Sep 17 00:00:00 2001 From: Brian Austin Date: Mon, 6 Mar 2017 08:07:59 -0600 Subject: ASoC: Add support for Cirrus Logic CS35L35 Amplifier This patch adds support for the Cirrus Logic CS35L35 9V Boosted Amplifier Signed-off-by: Brian Austin Signed-off-by: Mark Brown --- include/sound/cs35l35.h | 103 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 include/sound/cs35l35.h (limited to 'include/sound') diff --git a/include/sound/cs35l35.h b/include/sound/cs35l35.h new file mode 100644 index 000000000000..de92e452bf93 --- /dev/null +++ b/include/sound/cs35l35.h @@ -0,0 +1,103 @@ +/* + * linux/sound/cs35l35.h -- Platform data for CS35l35 + * + * Copyright (c) 2016 Cirrus Logic Inc. + * + * 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 __CS35L35_H +#define __CS35L35_H + +struct classh_cfg { + /* + * Class H Algorithm Control Variables + * You can either have it done + * automatically or you can adjust + * these variables for tuning + * + * if you do not enable the internal algorithm + * you will get a set of mixer controls for + * Class H tuning + * + * Section 4.3 of the datasheet + */ + bool classh_bst_override; + bool classh_algo_enable; + int classh_bst_max_limit; + int classh_mem_depth; + int classh_release_rate; + int classh_headroom; + int classh_wk_fet_disable; + int classh_wk_fet_delay; + int classh_wk_fet_thld; + int classh_vpch_auto; + int classh_vpch_rate; + int classh_vpch_man; +}; + +struct monitor_cfg { + /* + * Signal Monitor Data + * highly configurable signal monitoring + * data positioning and different types of + * monitoring data. + * + * Section 4.8.2 - 4.8.4 of the datasheet + */ + bool is_present; + bool imon_specs; + bool vmon_specs; + bool vpmon_specs; + bool vbstmon_specs; + bool vpbrstat_specs; + bool zerofill_specs; + u8 imon_dpth; + u8 imon_loc; + u8 imon_frm; + u8 vmon_dpth; + u8 vmon_loc; + u8 vmon_frm; + u8 vpmon_dpth; + u8 vpmon_loc; + u8 vpmon_frm; + u8 vbstmon_dpth; + u8 vbstmon_loc; + u8 vbstmon_frm; + u8 vpbrstat_dpth; + u8 vpbrstat_loc; + u8 vpbrstat_frm; + u8 zerofill_dpth; + u8 zerofill_loc; + u8 zerofill_frm; +}; + +struct cs35l35_platform_data { + + /* Stereo (2 Device) */ + bool stereo; + /* serial port drive strength */ + int sp_drv_str; + /* Boost Power Down with FET */ + bool bst_pdn_fet_on; + /* Boost Voltage : used if ClassH Algo Enabled */ + int bst_vctl; + /* Boost Converter Peak Current CTRL */ + int bst_ipk; + /* Amp Gain Zero Cross */ + bool gain_zc; + /* Audio Input Location */ + int aud_channel; + /* Advisory Input Location */ + int adv_channel; + /* Shared Boost for stereo */ + bool shared_bst; + /* ClassH Algorithm */ + struct classh_cfg classh_algo; + /* Monitor Config */ + struct monitor_cfg mon_cfg; +}; + +#endif /* __CS35L35_H */ -- cgit v1.2.3-59-g8ed1b From 8d45f2d23864ae1582d095c54605540cd3640169 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 8 Mar 2017 16:42:49 +0000 Subject: ASoC: cs35l35: Add for configuring drive mode in unused slots Add support for setting how the I2S pins are driven in unused slots, currently the chip will just use the default of drive 0, however this causes issues when multiple devices are attached to the same bus. Signed-off-by: Charles Keepax Acked-by: Brian Austin Signed-off-by: Mark Brown --- include/sound/cs35l35.h | 2 ++ sound/soc/codecs/cs35l35.c | 7 +++++++ sound/soc/codecs/cs35l35.h | 4 ++++ 3 files changed, 13 insertions(+) (limited to 'include/sound') diff --git a/include/sound/cs35l35.h b/include/sound/cs35l35.h index de92e452bf93..983c610eba2e 100644 --- a/include/sound/cs35l35.h +++ b/include/sound/cs35l35.h @@ -80,6 +80,8 @@ struct cs35l35_platform_data { bool stereo; /* serial port drive strength */ int sp_drv_str; + /* serial port drive in unused slots */ + int sp_drv_unused; /* Boost Power Down with FET */ bool bst_pdn_fet_on; /* Boost Voltage : used if ClassH Algo Enabled */ diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index 48b45dc904ea..5a9fe5addb86 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -789,6 +789,11 @@ static int cs35l35_codec_probe(struct snd_soc_codec *codec) CS35L35_SP_DRV_MASK, cs35l35->pdata.sp_drv_str << CS35L35_SP_DRV_SHIFT); + if (cs35l35->pdata.sp_drv_unused) + regmap_update_bits(cs35l35->regmap, CS35L35_SP_FMT_CTL3, + CS35L35_SP_I2S_DRV_MASK, + cs35l35->pdata.sp_drv_unused << + CS35L35_SP_I2S_DRV_SHIFT); if (classh->classh_algo_enable) { if (classh->classh_bst_override) @@ -1169,6 +1174,8 @@ static int cs35l35_handle_of_data(struct i2c_client *i2c_client, if (of_property_read_u32(np, "cirrus,sp-drv-strength", &val32) >= 0) pdata->sp_drv_str = val32; + if (of_property_read_u32(np, "cirrus,sp-drv-unused", &val32) >= 0) + pdata->sp_drv_unused = val32 | CS35L35_VALID_PDATA; pdata->stereo = of_property_read_bool(np, "cirrus,stereo-config"); diff --git a/sound/soc/codecs/cs35l35.h b/sound/soc/codecs/cs35l35.h index e27a7fef5fb1..c203081fc94c 100644 --- a/sound/soc/codecs/cs35l35.h +++ b/sound/soc/codecs/cs35l35.h @@ -190,6 +190,10 @@ #define CS35L35_AMP_GAIN_ZC_MASK 0x10 #define CS35L35_AMP_GAIN_ZC_SHIFT 4 +/* CS35L35_SP_FMT_CTL3 */ +#define CS35L35_SP_I2S_DRV_MASK 0x03 +#define CS35L35_SP_I2S_DRV_SHIFT 0 + /* Class H Algorithm Control */ #define CS35L35_CH_STEREO_MASK 0x40 #define CS35L35_CH_STEREO_SHIFT 6 -- cgit v1.2.3-59-g8ed1b From 77b329d1943d38a5acdbaf9d57754975bce701d4 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 6 Apr 2017 13:52:13 +0100 Subject: ASoC: cs35l35: Correct handling of PDN_DONE with external boost When using an external boost supply the PDN_DONE bit is not set, update the handling in this case to use to use an appropriate fixed delay. Signed-off-by: Charles Keepax Acked-by: Brian Austin Signed-off-by: Mark Brown --- include/sound/cs35l35.h | 2 ++ sound/soc/codecs/cs35l35.c | 32 ++++++++++++++++++++++++-------- 2 files changed, 26 insertions(+), 8 deletions(-) (limited to 'include/sound') diff --git a/include/sound/cs35l35.h b/include/sound/cs35l35.h index 983c610eba2e..88744bbd6728 100644 --- a/include/sound/cs35l35.h +++ b/include/sound/cs35l35.h @@ -96,6 +96,8 @@ struct cs35l35_platform_data { int adv_channel; /* Shared Boost for stereo */ bool shared_bst; + /* Specifies this amp is using an external boost supply */ + bool ext_bst; /* ClassH Algorithm */ struct classh_cfg classh_algo; /* Monitor Config */ diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index 1db07a6296a4..6ecb7ddae9cf 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -162,6 +162,27 @@ static bool cs35l35_precious_register(struct device *dev, unsigned int reg) } } +static int cs35l35_wait_for_pdn(struct cs35l35_private *cs35l35) +{ + int ret; + + if (cs35l35->pdata.ext_bst) { + usleep_range(5000, 5500); + return 0; + } + + reinit_completion(&cs35l35->pdn_done); + + ret = wait_for_completion_timeout(&cs35l35->pdn_done, + msecs_to_jiffies(100)); + if (ret == 0) { + dev_err(cs35l35->dev, "PDN_DONE did not complete\n"); + return -ETIMEDOUT; + } + + return 0; +} + static int cs35l35_sdin_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -191,14 +212,7 @@ static int cs35l35_sdin_event(struct snd_soc_dapm_widget *w, regmap_update_bits(cs35l35->regmap, CS35L35_AMP_DIG_VOL_CTL, CS35L35_AMP_DIGSFT_MASK, 0); - reinit_completion(&cs35l35->pdn_done); - - ret = wait_for_completion_timeout(&cs35l35->pdn_done, - msecs_to_jiffies(100)); - if (ret == 0) { - dev_err(codec->dev, "TIMEOUT PDN_DONE did not complete in 100ms\n"); - ret = -ETIMEDOUT; - } + ret = cs35l35_wait_for_pdn(cs35l35); regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, CS35L35_MCLK_DIS_MASK, @@ -1198,6 +1212,8 @@ static int cs35l35_handle_of_data(struct i2c_client *i2c_client, "cirrus,shared-boost"); } + pdata->ext_bst = of_property_read_bool(np, "cirrus,external-boost"); + pdata->gain_zc = of_property_read_bool(np, "cirrus,amp-gain-zc"); classh = of_get_child_by_name(np, "cirrus,classh-internal-algo"); -- cgit v1.2.3-59-g8ed1b From 06bdf385f66a53b335b324e28a43788b03e6f3e3 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 13 Apr 2017 16:52:09 +0100 Subject: ASoC: cs35l35: Allow user to configure IMON SCALE On the chip the IMON signal is a full 24-bits however normally only some of the bits will be sent over the bus. The chip provides a field to select which bits of the IMON will be sent back, this is the only feedback signal that has this feature. Add an additional entry to the cirrus,imon device tree property to allow the IMON scale parameter to be passed. Signed-off-by: Charles Keepax Acked-by: Brian Austin Acked-by: Rob Herring Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/cs35l35.txt | 4 ++-- include/sound/cs35l35.h | 1 + sound/soc/codecs/cs35l35.c | 22 +++++++++++++++------- sound/soc/codecs/cs35l35.h | 3 +++ 4 files changed, 21 insertions(+), 9 deletions(-) (limited to 'include/sound') diff --git a/Documentation/devicetree/bindings/sound/cs35l35.txt b/Documentation/devicetree/bindings/sound/cs35l35.txt index 457d176dcee0..016b768bc722 100644 --- a/Documentation/devicetree/bindings/sound/cs35l35.txt +++ b/Documentation/devicetree/bindings/sound/cs35l35.txt @@ -118,8 +118,8 @@ Optional Monitor Signal Format sub-node: Sections 7.44 - 7.53 lists values for the depth, location, and frame for each monitoring signal. - - cirrus,imon : 3 8 bit values to set the depth, location, and frame - of the IMON monitor signal. + - cirrus,imon : 4 8 bit values to set the depth, location, frame and ADC + scale of the IMON monitor signal. - cirrus,vmon : 3 8 bit values to set the depth, location, and frame of the VMON monitor signal. diff --git a/include/sound/cs35l35.h b/include/sound/cs35l35.h index 88744bbd6728..29da899e17e4 100644 --- a/include/sound/cs35l35.h +++ b/include/sound/cs35l35.h @@ -57,6 +57,7 @@ struct monitor_cfg { u8 imon_dpth; u8 imon_loc; u8 imon_frm; + u8 imon_scale; u8 vmon_dpth; u8 vmon_loc; u8 vmon_frm; diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index dc6591adc96d..f8aef5869b03 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -918,6 +918,11 @@ static int cs35l35_codec_probe(struct snd_soc_codec *codec) CS35L35_MON_FRM_MASK, monitor_config->imon_frm << CS35L35_MON_FRM_SHIFT); + regmap_update_bits(cs35l35->regmap, + CS35L35_IMON_SCALE_CTL, + CS35L35_IMON_SCALE_MASK, + monitor_config->imon_scale << + CS35L35_IMON_SCALE_SHIFT); } if (monitor_config->vpmon_specs) { regmap_update_bits(cs35l35->regmap, @@ -1161,7 +1166,9 @@ static int cs35l35_handle_of_data(struct i2c_client *i2c_client, struct classh_cfg *classh_config = &pdata->classh_algo; struct monitor_cfg *monitor_config = &pdata->mon_cfg; unsigned int val32 = 0; - u8 monitor_array[3]; + u8 monitor_array[4]; + const int imon_array_size = ARRAY_SIZE(monitor_array); + const int mon_array_size = imon_array_size - 1; int ret = 0; if (!np) @@ -1302,15 +1309,16 @@ static int cs35l35_handle_of_data(struct i2c_client *i2c_client, monitor_config->is_present = signal_format ? true : false; if (monitor_config->is_present) { ret = of_property_read_u8_array(signal_format, "cirrus,imon", - monitor_array, ARRAY_SIZE(monitor_array)); + monitor_array, imon_array_size); if (!ret) { monitor_config->imon_specs = true; monitor_config->imon_dpth = monitor_array[0]; monitor_config->imon_loc = monitor_array[1]; monitor_config->imon_frm = monitor_array[2]; + monitor_config->imon_scale = monitor_array[3]; } ret = of_property_read_u8_array(signal_format, "cirrus,vmon", - monitor_array, ARRAY_SIZE(monitor_array)); + monitor_array, mon_array_size); if (!ret) { monitor_config->vmon_specs = true; monitor_config->vmon_dpth = monitor_array[0]; @@ -1318,7 +1326,7 @@ static int cs35l35_handle_of_data(struct i2c_client *i2c_client, monitor_config->vmon_frm = monitor_array[2]; } ret = of_property_read_u8_array(signal_format, "cirrus,vpmon", - monitor_array, ARRAY_SIZE(monitor_array)); + monitor_array, mon_array_size); if (!ret) { monitor_config->vpmon_specs = true; monitor_config->vpmon_dpth = monitor_array[0]; @@ -1326,7 +1334,7 @@ static int cs35l35_handle_of_data(struct i2c_client *i2c_client, monitor_config->vpmon_frm = monitor_array[2]; } ret = of_property_read_u8_array(signal_format, "cirrus,vbstmon", - monitor_array, ARRAY_SIZE(monitor_array)); + monitor_array, mon_array_size); if (!ret) { monitor_config->vbstmon_specs = true; monitor_config->vbstmon_dpth = monitor_array[0]; @@ -1334,7 +1342,7 @@ static int cs35l35_handle_of_data(struct i2c_client *i2c_client, monitor_config->vbstmon_frm = monitor_array[2]; } ret = of_property_read_u8_array(signal_format, "cirrus,vpbrstat", - monitor_array, ARRAY_SIZE(monitor_array)); + monitor_array, mon_array_size); if (!ret) { monitor_config->vpbrstat_specs = true; monitor_config->vpbrstat_dpth = monitor_array[0]; @@ -1342,7 +1350,7 @@ static int cs35l35_handle_of_data(struct i2c_client *i2c_client, monitor_config->vpbrstat_frm = monitor_array[2]; } ret = of_property_read_u8_array(signal_format, "cirrus,zerofill", - monitor_array, ARRAY_SIZE(monitor_array)); + monitor_array, mon_array_size); if (!ret) { monitor_config->zerofill_specs = true; monitor_config->zerofill_dpth = monitor_array[0]; diff --git a/sound/soc/codecs/cs35l35.h b/sound/soc/codecs/cs35l35.h index 54e9ac536b20..5a6e43a87c4d 100644 --- a/sound/soc/codecs/cs35l35.h +++ b/sound/soc/codecs/cs35l35.h @@ -148,6 +148,9 @@ #define CS35L35_MON_FRM_MASK 0x80 #define CS35L35_MON_FRM_SHIFT 7 +#define CS35L35_IMON_SCALE_MASK 0xF8 +#define CS35L35_IMON_SCALE_SHIFT 3 + #define CS35L35_MS_MASK 0x80 #define CS35L35_MS_SHIFT 7 #define CS35L35_SPMODE_MASK 0x40 -- cgit v1.2.3-59-g8ed1b