[PATCH] powerpc: Fix PowerMac sound i2c

Benjamin Herrenschmidt benh at kernel.crashing.org
Sun Jan 8 15:52:36 EST 2006


My patch reworking the PowerMac i2c code break the sound drivers as they
used to rely on some broken behaviour of i2c-keywest that is gone now.
This patch should fix them (tested on a g5 with alsa only). It might
also fix an oops if the alsa driver hits an unsupported chip.

Signed-off-by: Benjamin Herrenschmidt <benh at kernel.crashing.org>

Index: linux-work/sound/ppc/tumbler.c
===================================================================
--- linux-work.orig/sound/ppc/tumbler.c	2005-11-24 17:19:14.000000000 +1100
+++ linux-work/sound/ppc/tumbler.c	2006-01-08 15:18:09.000000000 +1100
@@ -137,6 +137,22 @@ static int send_init_client(pmac_keywest
 	return 0;
 }
 
+static int tumbler_write_block(struct i2c_client *client, u8 reg, int len,
+			       u8 *values)
+{
+        union i2c_smbus_data data;
+        int err;
+
+        data.block[0] = len;
+	memcpy(&data.block[1], values, len);
+        err = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+                             I2C_SMBUS_WRITE, reg, I2C_SMBUS_I2C_BLOCK_DATA,
+                             &data);
+        return err;
+}
+
+
+
 
 static int tumbler_init_client(pmac_keywest_t *i2c)
 {
@@ -239,8 +255,7 @@ static int tumbler_set_master_volume(pma
 	block[4] = (right_vol >> 8)  & 0xff;
 	block[5] = (right_vol >> 0)  & 0xff;
   
-	if (i2c_smbus_write_block_data(mix->i2c.client, TAS_REG_VOL,
-				       6, block) < 0) {
+	if (tumbler_write_block(mix->i2c.client, TAS_REG_VOL, 6, block) < 0) {
 		snd_printk("failed to set volume \n");
 		return -EINVAL;
 	}
@@ -340,8 +355,7 @@ static int tumbler_set_drc(pmac_tumbler_
 		val[1] = 0;
 	}
 
-	if (i2c_smbus_write_block_data(mix->i2c.client, TAS_REG_DRC,
-				       2, val) < 0) {
+	if (tumbler_write_block(mix->i2c.client, TAS_REG_DRC, 2, val) < 0) {
 		snd_printk("failed to set DRC\n");
 		return -EINVAL;
 	}
@@ -376,8 +390,7 @@ static int snapper_set_drc(pmac_tumbler_
 	val[4] = 0x60;
 	val[5] = 0xa0;
 
-	if (i2c_smbus_write_block_data(mix->i2c.client, TAS_REG_DRC,
-				       6, val) < 0) {
+	if (tumbler_write_block(mix->i2c.client, TAS_REG_DRC, 6, val) < 0) {
 		snd_printk("failed to set DRC\n");
 		return -EINVAL;
 	}
@@ -481,8 +494,8 @@ static int tumbler_set_mono_volume(pmac_
 	vol = info->table[vol];
 	for (i = 0; i < info->bytes; i++)
 		block[i] = (vol >> ((info->bytes - i - 1) * 8)) & 0xff;
-	if (i2c_smbus_write_block_data(mix->i2c.client, info->reg,
-				       info->bytes, block) < 0) {
+	if (tumbler_write_block(mix->i2c.client, info->reg,
+				  info->bytes, block) < 0) {
 		snd_printk("failed to set mono volume %d\n", info->index);
 		return -EINVAL;
 	}
@@ -611,7 +624,7 @@ static int snapper_set_mix_vol1(pmac_tum
 		for (j = 0; j < 3; j++)
 			block[i * 3 + j] = (vol >> ((2 - j) * 8)) & 0xff;
 	}
-	if (i2c_smbus_write_block_data(mix->i2c.client, reg, 9, block) < 0) {
+	if (tumbler_write_block(mix->i2c.client, reg, 9, block) < 0) {
 		snd_printk("failed to set mono volume %d\n", reg);
 		return -EINVAL;
 	}
Index: linux-work/sound/oss/dmasound/tas_common.h
===================================================================
--- linux-work.orig/sound/oss/dmasound/tas_common.h	2005-11-24 17:19:14.000000000 +1100
+++ linux-work/sound/oss/dmasound/tas_common.h	2006-01-08 15:33:29.000000000 +1100
@@ -157,6 +157,21 @@ tas_mono_to_stereo(uint mono)
 	return mono | (mono<<8);
 }
 
+static int tas_write_block(struct i2c_client *client, u8 reg, int len, u8 *vals)
+{
+        union i2c_smbus_data data;
+        int err;
+
+        data.block[0] = len;
+	memcpy(&data.block[1], vals, len);
+        err = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+                             I2C_SMBUS_WRITE, reg, I2C_SMBUS_I2C_BLOCK_DATA,
+                             &data);
+        return err;
+}
+
+
+
 /*
  * Todo: make these functions a bit more efficient !
  */
@@ -178,10 +193,8 @@ tas_write_register(	struct tas_data_t *s
 	if (write_mode & WRITE_SHADOW)
 		memcpy(self->shadow[reg_num],data,reg_width);
 	if (write_mode & WRITE_HW) {
-		rc=i2c_smbus_write_block_data(self->client,
-					      reg_num,
-					      reg_width,
-					      data);
+		rc = tas_write_block(self->client, reg_num,
+				     reg_width, data);
 		if (rc < 0) {
 			printk("tas: I2C block write failed \n");  
 			return rc; 
@@ -199,10 +212,8 @@ tas_sync_register(	struct tas_data_t *se
 
 	if (reg_width==0 || self==NULL)
 		return -EINVAL;
-	rc=i2c_smbus_write_block_data(self->client,
-				      reg_num,
-				      reg_width,
-				      self->shadow[reg_num]);
+	rc = tas_write_block(self->client, reg_num,
+			     reg_width, self->shadow[reg_num]);
 	if (rc < 0) {
 		printk("tas: I2C block write failed \n");
 		return rc;
Index: linux-work/sound/ppc/pmac.c
===================================================================
--- linux-work.orig/sound/ppc/pmac.c	2005-12-19 16:13:48.000000000 +1100
+++ linux-work/sound/ppc/pmac.c	2006-01-08 15:37:10.000000000 +1100
@@ -74,7 +74,7 @@ static int snd_pmac_dbdma_alloc(pmac_t *
 
 static void snd_pmac_dbdma_free(pmac_t *chip, pmac_dbdma_t *rec)
 {
-	if (rec) {
+	if (rec->space) {
 		unsigned int rsize = sizeof(struct dbdma_cmd) * (rec->size + 1);
 
 		dma_free_coherent(&chip->pdev->dev, rsize, rec->space, rec->dma_base);
@@ -895,6 +895,7 @@ static int __init snd_pmac_detect(pmac_t
 	chip->can_capture = 1;
 	chip->num_freqs = ARRAY_SIZE(awacs_freqs);
 	chip->freq_table = awacs_freqs;
+	chip->pdev = NULL;
 
 	chip->control_mask = MASK_IEPC | MASK_IEE | 0x11; /* default */
 





More information about the Linuxppc-dev mailing list