summary refs log tree commit diff
diff options
context:
space:
mode:
authorCristian Ciocaltea <cristian.ciocaltea@collabora.com>2023-09-15 19:15:47 +0300
committerCristian Ciocaltea <cristian.ciocaltea@collabora.com>2023-09-15 19:15:47 +0300
commitae4f9e9d596068d3b2137e55aaf17d2efc568c1c (patch)
tree5faf433117e56133f7bfd7b5473af2e0943db7bc
parent96f579f5869bad3edcc6a6c25cd9db5b6b6369de (diff)
parente26b5a7f1f87e12746c76b3ee9858488b7884515 (diff)
downloadlinux-ae4f9e9d596068d3b2137e55aaf17d2efc568c1c.tar.gz
Merge branch 6.1/features/cirrus-shared-boost
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
-rw-r--r--Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml19
-rw-r--r--include/sound/cs35l41.h12
-rw-r--r--sound/soc/codecs/cs35l41.c90
3 files changed, 114 insertions, 7 deletions
diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml
index 51d815d0c696..28c8e6931f4e 100644
--- a/Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml
+++ b/Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml
@@ -140,6 +140,25 @@ properties:
     minimum: 0
     maximum: 5
 
+  cirrus,shared-boost-passive:
+    description:
+      Boolean which specifies that the amplifier uses shared boost
+      and is the passive amp. Shared boost allows two amplifiers to share
+      a single boost circuit by communicating on the MDSYNC bus. The passive
+      amplifier does not control the boost and receives data from
+      the active amplifier. GPIO1 should be configured for Sync when
+      shared boost is used. Shared boost is not compatible with External boost.
+    type: boolean
+
+  cirrus,shared-boost-active:
+    description:
+      Boolean which specifies that the amplifier uses shared boost
+      and is the active amp. The active amplifier controls the boost
+      and sends data to the passive amplifier. GPIO1 should be configured
+      for Sync when shared boost is used. Shared boost is not compatible
+      with External boost.
+    type: boolean
+
 required:
   - compatible
   - reg
diff --git a/include/sound/cs35l41.h b/include/sound/cs35l41.h
index 9ac5918269a5..d1c248cd3315 100644
--- a/include/sound/cs35l41.h
+++ b/include/sound/cs35l41.h
@@ -678,6 +678,8 @@
 #define CS35L36_PUP_DONE_IRQ_UNMASK	0x5F
 #define CS35L36_PUP_DONE_IRQ_MASK	0xBF
 
+#define CS35L41_SYNC_EN_MASK		(1 << 8)
+
 #define CS35L41_AMP_SHORT_ERR		0x80000000
 #define CS35L41_BST_SHORT_ERR		0x0100
 #define CS35L41_TEMP_WARN		0x8000
@@ -686,6 +688,7 @@
 #define CS35L41_BST_DCM_UVP_ERR		0x80
 #define CS35L41_OTP_BOOT_DONE		0x02
 #define CS35L41_PLL_UNLOCK		0x10
+#define CS35L41_PLL_LOCK		0x02
 #define CS35L41_OTP_BOOT_ERR		0x80000000
 
 #define CS35L41_AMP_SHORT_ERR_RLS	0x02
@@ -705,6 +708,8 @@
 #define CS35L41_INT1_MASK_DEFAULT	0x7FFCFE3F
 #define CS35L41_INT1_UNMASK_PUP		0xFEFFFFFF
 #define CS35L41_INT1_UNMASK_PDN		0xFF7FFFFF
+#define CS35L41_INT3_MASK_DEFAULT	0xFFFF87FF
+#define CS35L41_INT3_UNMASK_PLL_LOCK	0xFFFF87FD
 
 #define CS35L41_GPIO_DIR_MASK		0x80000000
 #define CS35L41_GPIO_DIR_SHIFT		31
@@ -745,6 +750,12 @@ enum cs35l41_boost_type {
 	CS35L41_EXT_BOOST_NO_VSPK_SWITCH,
 };
 
+enum cs35l41_shared_boost {
+    SHARED_BOOST_DISABLED,
+    SHARED_BOOST_ACTIVE,
+    SHARED_BOOST_PASSIVE,
+};
+
 enum cs35l41_clk_ids {
 	CS35L41_CLKID_SCLK = 0,
 	CS35L41_CLKID_LRCLK = 1,
@@ -789,6 +800,7 @@ struct cs35l41_hw_cfg {
 	unsigned int spk_pos;
 
 	enum cs35l41_boost_type bst_type;
+	enum cs35l41_shared_boost shared_boost;
 };
 
 struct cs35l41_otp_packed_element_t {
diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c
index 2f4b0ee93ace..dc850150e816 100644
--- a/sound/soc/codecs/cs35l41.c
+++ b/sound/soc/codecs/cs35l41.c
@@ -487,6 +487,19 @@ static irqreturn_t cs35l41_irq(int irq, void *data)
 		ret = IRQ_HANDLED;
 	}
 
+	if (status[2] & CS35L41_PLL_LOCK) {
+		regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS3,
+			     CS35L41_PLL_LOCK);
+		if (cs35l41->hw_cfg.shared_boost == SHARED_BOOST_PASSIVE) {
+			/* GPIO2 as open drain interrupt, GPIO1 as SYNC */
+			regmap_write(cs35l41->regmap, CS35L41_GPIO_PAD_CONTROL,
+				     0x02020000);
+			regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL3,
+					   CS35L41_SYNC_EN_MASK,
+					   CS35L41_SYNC_EN_MASK);
+		}
+	}
+
 done:
 	pm_runtime_mark_last_busy(cs35l41->dev);
 	pm_runtime_put_autosuspend(cs35l41->dev);
@@ -541,6 +554,14 @@ static int cs35l41_main_amp_event(struct snd_soc_dapm_widget *w,
 		regmap_multi_reg_write_bypassed(cs35l41->regmap,
 						cs35l41_pdn_patch,
 						ARRAY_SIZE(cs35l41_pdn_patch));
+		if (cs35l41->hw_cfg.shared_boost == SHARED_BOOST_PASSIVE) {
+			regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL3,
+					   CS35L41_SYNC_EN_MASK, 0);
+			/* GPIO2 as open drain interrupt, GPIO1 as hi-z input */
+			regmap_write(cs35l41->regmap, CS35L41_GPIO_PAD_CONTROL,
+				     0x02000000);
+		}
+
 		break;
 	default:
 		dev_err(cs35l41->dev, "Invalid event = 0x%x\n", event);
@@ -926,6 +947,28 @@ static int cs35l41_dai_set_sysclk(struct snd_soc_dai *dai,
 	return 0;
 }
 
+static const struct reg_sequence cs35l41_active_seq[] = {
+	/* SYNC_BST_CTL_RX_EN = 1; SYNC_BST_CTL_TX_EN = 1*/
+	{CS35L41_MDSYNC_EN,		0x00003200},
+	/* BST_CTL_SEL = MDSYNC */
+	{CS35L41_BSTCVRT_VCTRL2,	0x00000002},
+	/* WKFET_AMP_EN = 1; SYNC_EN = 1; CLASSH_EN= 1 */
+	{CS35L41_PWR_CTRL3,		0x01000110},
+};
+
+static const struct reg_sequence cs35l41_passive_seq[] = {
+	/* GPIO2 as open drain interrupt, GPIO1 as hi-z input */
+	{CS35L41_GPIO_PAD_CONTROL,	0x02000000},
+	/* SYNC_BST_CTL_RX_EN = 0; SYNC_BST_CTL_TX_EN = 1 */
+	{CS35L41_MDSYNC_EN,		0x00001200},
+	/* BST_EN = 0 */
+	{CS35L41_PWR_CTRL2,		0x00003300},
+	/* BST_CTL_SEL = CLASSH */
+	{CS35L41_BSTCVRT_VCTRL2,	0x00000001},
+	/* WKFET_AMP_EN = 1; SYNC_EN = 0; CLASSH_EN= 1 */
+	{CS35L41_PWR_CTRL3,		0x01000010},
+};
+
 static int cs35l41_set_pdata(struct cs35l41_private *cs35l41)
 {
 	struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
@@ -942,6 +985,24 @@ static int cs35l41_set_pdata(struct cs35l41_private *cs35l41)
 	if (ret)
 		return ret;
 
+	if (cs35l41->hw_cfg.shared_boost == SHARED_BOOST_ACTIVE) {
+		ret = regmap_multi_reg_write(cs35l41->regmap,
+					     cs35l41_active_seq,
+					     ARRAY_SIZE(cs35l41_active_seq));
+		if (ret < 0)
+			dev_err(cs35l41->dev,
+				"Active shared boost seq failed %d\n", ret);
+	}
+
+	if (cs35l41->hw_cfg.shared_boost == SHARED_BOOST_PASSIVE) {
+		ret = regmap_multi_reg_write(cs35l41->regmap,
+					     cs35l41_passive_seq,
+					     ARRAY_SIZE(cs35l41_passive_seq));
+		if (ret < 0)
+			dev_err(cs35l41->dev,
+				"Passive shared boost seq failed %d\n", ret);
+	}
+
 	/* Optional */
 	if (hw_cfg->dout_hiz <= CS35L41_ASP_DOUT_HIZ_MASK && hw_cfg->dout_hiz >= 0)
 		regmap_update_bits(cs35l41->regmap, CS35L41_SP_HIZ_CTRL, CS35L41_ASP_DOUT_HIZ_MASK,
@@ -1045,6 +1106,14 @@ static int cs35l41_handle_pdata(struct device *dev, struct cs35l41_hw_cfg *hw_cf
 	if (ret >= 0)
 		hw_cfg->bst_type = val;
 
+	if (device_property_read_bool(dev, "cirrus,shared-boost-passive")) {
+		hw_cfg->shared_boost = SHARED_BOOST_PASSIVE;
+	}
+
+	if (device_property_read_bool(dev, "cirrus,shared-boost-active")) {
+		hw_cfg->shared_boost = SHARED_BOOST_ACTIVE;
+	}
+
 	ret = device_property_read_u32(dev, "cirrus,boost-peak-milliamp", &val);
 	if (ret >= 0)
 		hw_cfg->bst_ipk = val;
@@ -1284,6 +1353,10 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *
 	/* Set interrupt masks for critical errors */
 	regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1,
 		     CS35L41_INT1_MASK_DEFAULT);
+	if (cs35l41->hw_cfg.shared_boost == SHARED_BOOST_PASSIVE)
+		regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK3,
+			     CS35L41_INT3_UNMASK_PLL_LOCK);
+
 
 	ret = devm_request_threaded_irq(cs35l41->dev, cs35l41->irq, NULL, cs35l41_irq,
 					IRQF_ONESHOT | IRQF_SHARED | irq_pol,
@@ -1307,12 +1380,12 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *
 	if (ret < 0)
 		goto err;
 
-	pm_runtime_set_autosuspend_delay(cs35l41->dev, 3000);
-	pm_runtime_use_autosuspend(cs35l41->dev);
-	pm_runtime_mark_last_busy(cs35l41->dev);
-	pm_runtime_set_active(cs35l41->dev);
-	pm_runtime_get_noresume(cs35l41->dev);
-	pm_runtime_enable(cs35l41->dev);
+//	pm_runtime_set_autosuspend_delay(cs35l41->dev, 3000);
+//	pm_runtime_use_autosuspend(cs35l41->dev);
+//	pm_runtime_mark_last_busy(cs35l41->dev);
+//	pm_runtime_set_active(cs35l41->dev);
+//	pm_runtime_get_noresume(cs35l41->dev);
+//	pm_runtime_enable(cs35l41->dev);
 
 	ret = devm_snd_soc_register_component(cs35l41->dev,
 					      &soc_component_dev_cs35l41,
@@ -1322,7 +1395,7 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *
 		goto err_pm;
 	}
 
-	pm_runtime_put_autosuspend(cs35l41->dev);
+//	pm_runtime_put_autosuspend(cs35l41->dev);
 
 	dev_info(cs35l41->dev, "Cirrus Logic CS35L41 (%x), Revision: %02X\n",
 		 regid, reg_revid);
@@ -1349,6 +1422,9 @@ void cs35l41_remove(struct cs35l41_private *cs35l41)
 	pm_runtime_disable(cs35l41->dev);
 
 	regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1, 0xFFFFFFFF);
+	if (cs35l41->hw_cfg.shared_boost == SHARED_BOOST_PASSIVE)
+		regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK3,
+			     CS35L41_INT3_MASK_DEFAULT);
 	kfree(cs35l41->dsp.system_name);
 	wm_adsp2_remove(&cs35l41->dsp);
 	cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type);