<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">Return-Path: &lt;linuxppc-dev-bounces@ozlabs.org&gt;
X-Original-To: colinomail@colino.net
Delivered-To: colinomail@colino.net
Received: by paperstreet.colino.net (Postfix, from userid 1015)
	id C0253101D9; Mon, 11 Apr 2005 04:03:33 +0200 (CEST)
Received: from ozlabs.org (ozlabs.org [203.10.76.45])
	by paperstreet.colino.net (Postfix) with ESMTP id 89C25101DB
	for &lt;colin@colino.net&gt;; Mon, 11 Apr 2005 04:03:26 +0200 (CEST)
Received: from ozlabs.org (localhost [127.0.0.1])
	by ozlabs.org (Postfix) with ESMTP id CEC8B67B4C;
	Mon, 11 Apr 2005 12:03:19 +1000 (EST)
X-Original-To: linuxppc-dev@ozlabs.org
Delivered-To: linuxppc-dev@ozlabs.org
Received: from gate.crashing.org (gate.crashing.org [63.228.1.57])
	(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
	(Client did not present a certificate)
	by ozlabs.org (Postfix) with ESMTP id 83FAC67B45
	for &lt;linuxppc-dev@ozlabs.org&gt;; Mon, 11 Apr 2005 12:03:17 +1000 (EST)
Received: from gaston (localhost [127.0.0.1])
	by gate.crashing.org (8.12.8/8.12.8) with ESMTP id j3B1wmgJ030211;
	Sun, 10 Apr 2005 20:58:49 -0500
From: Benjamin Herrenschmidt &lt;benh@kernel.crashing.org&gt;
To: Andrew Morton &lt;akpm@osdl.org&gt;
Content-Type: text/plain
Date: Mon, 11 Apr 2005 12:00:54 +1000
Message-Id: &lt;1113184854.9567.522.camel@gaston&gt;
Mime-Version: 1.0
X-Mailer: Evolution 2.0.4 
Content-Transfer-Encoding: 7bit
Cc: Takashi Iwai &lt;tiwai@suse.de&gt;,
	linuxppc-dev list &lt;linuxppc-dev@ozlabs.org&gt;,
	"debian-powerpc@lists.debian.org" &lt;debian-powerpc@lists.debian.org&gt;
Subject: [PATCH] pmac: Improve sleep code of tumbler driver
X-BeenThere: linuxppc-dev@ozlabs.org
X-Mailman-Version: 2.1.5
Precedence: list
List-Id: Linux on PowerPC Developers Mail List &lt;linuxppc-dev.ozlabs.org&gt;
List-Unsubscribe: &lt;https://ozlabs.org/mailman/listinfo/linuxppc-dev&gt;,
	&lt;mailto:linuxppc-dev-request@ozlabs.org?subject=unsubscribe&gt;
List-Archive: &lt;http://ozlabs.org/pipermail/linuxppc-dev&gt;
List-Post: &lt;mailto:linuxppc-dev@ozlabs.org&gt;
List-Help: &lt;mailto:linuxppc-dev-request@ozlabs.org?subject=help&gt;
List-Subscribe: &lt;https://ozlabs.org/mailman/listinfo/linuxppc-dev&gt;,
	&lt;mailto:linuxppc-dev-request@ozlabs.org?subject=subscribe&gt;
Sender: linuxppc-dev-bounces@ozlabs.org
Errors-To: linuxppc-dev-bounces@ozlabs.org
X-Spam-Checker-Version: SpamAssassin 2.64 (2004-01-11) on 
	paperstreet.colino.net
X-Spam-Level: 
X-Spam-Status: No, hits=-2.4 required=5.0 tests=AWL,BAYES_20 autolearn=no 
	version=2.64
X-UIDL: 9EW!!Xm&lt;"!PO?!!\Xh!!
Status: RO

Hi !

This patch (applies on top of my previous one adding support for newer
machines) improves the behaviour of the "tumbler/snapper" driver used on
newer PowerMacs during sleep. It properly set the HW mutes to shut down
amplifiers and does an analog shutdown of the codec. That might improve
power consumption during sleep on a number of machines.

Signed-off-by: Benjamin Herrenschmidt &lt;benh@kernel.crashing.org&gt;

Index: linux-work/sound/ppc/tumbler.c
===================================================================
--- linux-work.orig/sound/ppc/tumbler.c	2005-04-11 10:50:18.000000000 +1000
+++ linux-work/sound/ppc/tumbler.c	2005-04-11 11:57:07.000000000 +1000
@@ -94,12 +94,17 @@
 	pmac_gpio_t hp_detect;
 	int headphone_irq;
 	unsigned int master_vol[2];
+	unsigned int save_master_switch[2];
 	unsigned int master_switch[2];
 	unsigned int mono_vol[VOL_IDX_LAST_MONO];
 	unsigned int mix_vol[VOL_IDX_LAST_MIX][2]; /* stereo volumes for tas3004 */
 	int drc_range;
 	int drc_enable;
 	int capture_source;
+	int anded_reset;
+	int auto_mute_notify;
+	int reset_on_sleep;
+	u8  acs;
 } pmac_tumbler_t;
 
 
@@ -654,7 +659,8 @@
 
 
 /*
- * mute switches
+ * mute switches. FIXME: Turn that into software mute when both outputs are muted
+ * to avoid codec reset on ibook M7
  */
 
 enum { TUMBLER_MUTE_HP, TUMBLER_MUTE_AMP };
@@ -696,8 +702,11 @@
 {
 	if (! mix-&gt;i2c.client)
 		return -ENODEV;
-	return i2c_smbus_write_byte_data(mix-&gt;i2c.client, TAS_REG_ACS,
-					 mix-&gt;capture_source ? 2 : 0);
+	if (mix-&gt;capture_source)
+		mix-&gt;acs = mix-&gt;acs |= 2;
+	else
+		mix-&gt;acs &amp;= ~2;
+	return i2c_smbus_write_byte_data(mix-&gt;i2c.client, TAS_REG_ACS, mix-&gt;acs);
 }
 
 static int snapper_info_capture_source(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
@@ -855,8 +864,7 @@
 
 static struct work_struct device_change;
 
-static void
-device_change_handler(void *self)
+static void device_change_handler(void *self)
 {
 	pmac_t *chip = (pmac_t*) self;
 	pmac_tumbler_t *mix;
@@ -865,6 +873,33 @@
 		return;
 
 	mix = chip-&gt;mixer_data;
+	snd_assert(mix, return);
+
+	if (tumbler_detect_headphone(chip)) {
+		/* mute speaker */
+		check_mute(chip, &amp;mix-&gt;hp_mute, 0, mix-&gt;auto_mute_notify,
+			   chip-&gt;master_sw_ctl);
+		if (mix-&gt;anded_reset)
+			big_mdelay(10);
+		check_mute(chip, &amp;mix-&gt;amp_mute, 1, mix-&gt;auto_mute_notify,
+			   chip-&gt;speaker_sw_ctl);
+		mix-&gt;drc_enable = 0;
+	} else {
+		/* unmute speaker */
+		check_mute(chip, &amp;mix-&gt;amp_mute, 0, mix-&gt;auto_mute_notify,
+			   chip-&gt;speaker_sw_ctl);
+		if (mix-&gt;anded_reset)
+			big_mdelay(10);
+		check_mute(chip, &amp;mix-&gt;hp_mute, 1, mix-&gt;auto_mute_notify,
+			   chip-&gt;master_sw_ctl);
+		mix-&gt;drc_enable = 1;
+	}
+	if (mix-&gt;auto_mute_notify) {
+		snd_ctl_notify(chip-&gt;card, SNDRV_CTL_EVENT_MASK_VALUE,
+				       &amp;chip-&gt;hp_detect_ctl-&gt;id);
+		snd_ctl_notify(chip-&gt;card, SNDRV_CTL_EVENT_MASK_VALUE,
+			       &amp;chip-&gt;drc_sw_ctl-&gt;id);
+	}
 
 	/* first set the DRC so the speaker do not explode -ReneR */
 	if (chip-&gt;model == PMAC_TUMBLER)
@@ -879,31 +914,11 @@
 static void tumbler_update_automute(pmac_t *chip, int do_notify)
 {
 	if (chip-&gt;auto_mute) {
-		pmac_tumbler_t *mix = chip-&gt;mixer_data;
+		pmac_tumbler_t *mix;
+		mix = chip-&gt;mixer_data;
 		snd_assert(mix, return);
-		if (tumbler_detect_headphone(chip)) {
-			/* mute speaker */
-			check_mute(chip, &amp;mix-&gt;amp_mute, 1, do_notify, chip-&gt;speaker_sw_ctl);
-			check_mute(chip, &amp;mix-&gt;hp_mute, 0, do_notify, chip-&gt;master_sw_ctl);
-			mix-&gt;drc_enable = 0;
-
-		} else {
-			/* unmute speaker */
-			check_mute(chip, &amp;mix-&gt;amp_mute, 0, do_notify, chip-&gt;speaker_sw_ctl);
-			check_mute(chip, &amp;mix-&gt;hp_mute, 1, do_notify, chip-&gt;master_sw_ctl);
-			mix-&gt;drc_enable = 1;
-		}
-		if (do_notify) {
-			snd_ctl_notify(chip-&gt;card, SNDRV_CTL_EVENT_MASK_VALUE,
-				       &amp;chip-&gt;hp_detect_ctl-&gt;id);
-			snd_ctl_notify(chip-&gt;card, SNDRV_CTL_EVENT_MASK_VALUE,
-			               &amp;chip-&gt;drc_sw_ctl-&gt;id);
-		}
-
-		/* finally we need to schedule an update of the mixer values
-		   (master and DRC are enough for now) -ReneR */
+		mix-&gt;auto_mute_notify = do_notify;
 		schedule_work(&amp;device_change);
-
 	}
 }
 #endif /* PMAC_SUPPORT_AUTOMUTE */
@@ -1002,15 +1017,53 @@
 {
 	pmac_tumbler_t *mix = chip-&gt;mixer_data;
 
-	write_audio_gpio(&amp;mix-&gt;audio_reset, 0);
-	big_mdelay(200);
-	write_audio_gpio(&amp;mix-&gt;audio_reset, 1);
-	big_mdelay(100);
-	write_audio_gpio(&amp;mix-&gt;audio_reset, 0);
-	big_mdelay(100);
+	if (mix-&gt;anded_reset) {
+		write_audio_gpio(&amp;mix-&gt;hp_mute, 0);
+		write_audio_gpio(&amp;mix-&gt;amp_mute, 0);
+		big_mdelay(200);
+		write_audio_gpio(&amp;mix-&gt;hp_mute, 1);
+		write_audio_gpio(&amp;mix-&gt;amp_mute, 1);
+		big_mdelay(100);
+		write_audio_gpio(&amp;mix-&gt;hp_mute, 0);
+		write_audio_gpio(&amp;mix-&gt;amp_mute, 0);
+		big_mdelay(100);
+	} else {
+		write_audio_gpio(&amp;mix-&gt;audio_reset, 0);
+		big_mdelay(200);
+		write_audio_gpio(&amp;mix-&gt;audio_reset, 1);
+		big_mdelay(100);
+		write_audio_gpio(&amp;mix-&gt;audio_reset, 0);
+		big_mdelay(100);
+	}
 }
 
 #ifdef CONFIG_PMAC_PBOOK
+/* suspend mixer */
+static void tumbler_suspend(pmac_t *chip)
+{
+	pmac_tumbler_t *mix = chip-&gt;mixer_data;
+
+	if (mix-&gt;headphone_irq &gt;= 0)
+		disable_irq(mix-&gt;headphone_irq);
+	mix-&gt;save_master_switch[0] = mix-&gt;master_switch[0];
+	mix-&gt;save_master_switch[1] = mix-&gt;master_switch[1];
+	mix-&gt;master_switch[0] = mix-&gt;master_switch[1] = 0;
+	tumbler_set_master_volume(mix);
+	if (!mix-&gt;anded_reset) {
+		write_audio_gpio(&amp;mix-&gt;amp_mute, 1);
+		write_audio_gpio(&amp;mix-&gt;hp_mute, 1);
+	}
+	if (chip-&gt;model == PMAC_SNAPPER) {
+		mix-&gt;acs |= 1;
+		i2c_smbus_write_byte_data(mix-&gt;i2c.client, TAS_REG_ACS, mix-&gt;acs);
+	}
+	if (mix-&gt;anded_reset) {
+		write_audio_gpio(&amp;mix-&gt;amp_mute, 1);
+		write_audio_gpio(&amp;mix-&gt;hp_mute, 1);
+	} else
+		write_audio_gpio(&amp;mix-&gt;audio_reset, 1);
+}
+
 /* resume mixer */
 static void tumbler_resume(pmac_t *chip)
 {
@@ -1018,6 +1071,9 @@
 
 	snd_assert(mix, return);
 
+	mix-&gt;acs &amp;= ~1;
+	mix-&gt;master_switch[0] = mix-&gt;save_master_switch[0];
+	mix-&gt;master_switch[1] = mix-&gt;save_master_switch[1];
 	tumbler_reset_audio(chip);
 	if (mix-&gt;i2c.client &amp;&amp; mix-&gt;i2c.init_client) {
 		if (mix-&gt;i2c.init_client(&amp;mix-&gt;i2c) &lt; 0)
@@ -1041,6 +1097,8 @@
 	tumbler_set_master_volume(mix);
 	if (chip-&gt;update_automute)
 		chip-&gt;update_automute(chip, 0);
+	if (mix-&gt;headphone_irq &gt;= 0)
+		enable_irq(mix-&gt;headphone_irq);
 }
 #endif
 
@@ -1103,9 +1161,9 @@
 	int i, err;
 	pmac_tumbler_t *mix;
 	u32 *paddr;
-	struct device_node *tas_node;
+	struct device_node *tas_node, *np;
 	char *chipname;
-
+	
 #ifdef CONFIG_KMOD
 	if (current-&gt;fs-&gt;root)
 		request_module("i2c-keywest");
@@ -1119,7 +1177,18 @@
 
 	chip-&gt;mixer_data = mix;
 	chip-&gt;mixer_free = tumbler_cleanup;
+	mix-&gt;anded_reset = 0;
+	mix-&gt;reset_on_sleep = 1;
 
+	for (np = chip-&gt;node-&gt;child; np; np = np-&gt;sibling) {
+		if (!strcmp(np-&gt;name, "sound")) {
+			if (get_property(np, "has-anded-reset", NULL))
+				mix-&gt;anded_reset = 1;
+			if (get_property(np, "layout-id", NULL))
+				mix-&gt;reset_on_sleep = 0;
+			break;
+		}
+	}  
 	if ((err = tumbler_init(chip)) &lt; 0)
 		return err;
 
@@ -1178,6 +1247,7 @@
 		return err;
 
 #ifdef CONFIG_PMAC_PBOOK
+	chip-&gt;suspend = tumbler_suspend;
 	chip-&gt;resume = tumbler_resume;
 #endif
 


_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev

</pre></body></html>