---
 sound/oss/at32dac.c |   72 +++++++++++++++++++++++++++++++---------------------
 1 file changed, 43 insertions(+), 29 deletions(-)

Index: linux-2.6.18-avr32/sound/oss/at32dac.c
===================================================================
--- linux-2.6.18-avr32.orig/sound/oss/at32dac.c	2006-11-01 14:30:47.000000000 +0100
+++ linux-2.6.18-avr32/sound/oss/at32dac.c	2006-11-01 14:32:05.000000000 +0100
@@ -71,6 +71,7 @@ struct at32_dac {
 	struct dma_request_cyclic req;
 
 	struct clk *mck;
+	struct clk *sample_clk;
 	struct platform_device *pdev;
 	int busy;
 	int playing;
@@ -116,24 +117,6 @@ static void at32dac_update_dma_tail(stru
 	}
 }
 
-static int at32dac_start_genclock(struct at32_dac *dac)
-{
-	unsigned int div;
-
-	div = ((clk_get_rate(boot_cpu_data.clk) + 256 * dac->dsp_settings.sample_rate)
-	       / (512 * dac->dsp_settings.sample_rate) - 1);
-	pr_debug("Real sample rate: %llu (div=%u)\n",
-		 boot_cpu_data.cpu_hz / (512 * (div + 1)), div);
-	writel((div << 8) | 0x16, (void __iomem *)(0xfff00060 + 4 * 6));
-
-	return 0;
-}
-
-static void at32dac_stop_genclock(struct at32_dac *dac)
-{
-	writel(0, (void __iomem *)(0xfff00060 + 4 * 6));
-}
-
 static int at32dac_start(struct at32_dac *dac)
 {
 	int ret;
@@ -143,13 +126,11 @@ static int at32dac_start(struct at32_dac
 
 	memset(dac->dma.buf, 0, DMA_BUFFER_SIZE);
 
-	ret = at32dac_start_genclock(dac);
-	if (ret)
-		return ret;
+	clk_enable(dac->sample_clk);
 
 	ret = dma_prepare_request_cyclic(dac->req.req.dmac, &dac->req);
 	if (ret)
-		goto out_stop_genclock;
+		goto out_stop_clock;
 
 	pr_debug("Starting DMA...\n");
 	ret = dma_start_request(dac->req.req.dmac, dac->req.req.channel);
@@ -164,8 +145,8 @@ static int at32dac_start(struct at32_dac
 out_stop_request:
 	dma_stop_request(dac->req.req.dmac,
 			 dac->req.req.channel);
-out_stop_genclock:
-	at32dac_stop_genclock(dac);
+out_stop_clock:
+	clk_disable(dac->sample_clk);
 	return ret;
 }
 
@@ -176,7 +157,7 @@ static int at32dac_stop(struct at32_dac 
 		dac_writel(dac, DATA, 0);
 		dac_writel(dac, CTRL, 0);
 		dac->playing = 0;
-		at32dac_stop_genclock(dac);
+		clk_disable(dac->sample_clk);
 	}
 
 	return 0;
@@ -360,6 +341,26 @@ static int at32dac_set_format(struct at3
 	return 0;
 }
 
+static int at32dac_set_sample_rate(struct at32_dac *dac, unsigned long rate)
+{
+	unsigned long new_rate;
+	int ret;
+
+	ret = clk_set_rate(dac->sample_clk, 256 * rate);
+	if (ret < 0)
+		return ret;
+
+	/* TODO: mplayer seems to have a problem with this */
+#if 0
+	new_rate = clk_get_rate(dac->sample_clk);
+	dac->dsp_settings.sample_rate = new_rate / 256;
+#else
+	dac->dsp_settings.sample_rate = rate;
+#endif
+
+	return 0;
+}
+
 static ssize_t at32dac_dsp_write(struct file *file,
 				 const char __user *buffer,
 				 size_t count, loff_t *ppos)
@@ -449,7 +450,9 @@ static int at32dac_dsp_ioctl(struct inod
 			return -EFAULT;
 		if (val >= 0) {
 			at32dac_stop(dac);
-			dac->dsp_settings.sample_rate = val;
+			ret = at32dac_set_sample_rate(dac, val);
+			if (ret)
+				return ret;
 		}
 		return put_user(dac->dsp_settings.sample_rate, up);
 
@@ -534,10 +537,11 @@ static int at32dac_dsp_open(struct inode
 	dac->dma.head = dac->dma.tail = 0;
 
 	/* FIXME: What are the correct defaults?  */
-	dac->dsp_settings.format = AFMT_S16_BE;
 	dac->dsp_settings.channels = 2;
-	dac->dsp_settings.sample_rate = 8000;
-	dac->dsp_settings.input_order = 2;
+	at32dac_set_format(dac, AFMT_S16_BE);
+	ret = at32dac_set_sample_rate(dac, 8000);
+	if (ret)
+		goto out;
 
 	file->private_data = dac;
 	dac->busy = 1;
@@ -578,6 +582,7 @@ static int __devinit at32dac_probe(struc
 	struct at32_dac *dac;
 	struct resource *regs;
 	struct clk *mck;
+	struct clk *sample_clk;
 	int irq;
 	int ret;
 
@@ -594,6 +599,11 @@ static int __devinit at32dac_probe(struc
 	mck = clk_get(&pdev->dev, "mck");
 	if (IS_ERR(mck))
 		return PTR_ERR(mck);
+	sample_clk = clk_get(&pdev->dev, "sample_clk");
+	if (IS_ERR(sample_clk)) {
+		ret = PTR_ERR(sample_clk);
+		goto out_put_mck;
+	}
 	clk_enable(mck);
 
 	ret = -ENOMEM;
@@ -606,6 +616,7 @@ static int __devinit at32dac_probe(struc
 	init_waitqueue_head(&dac->write_wait);
 	dac->pdev = pdev;
 	dac->mck = mck;
+	dac->sample_clk = sample_clk;
 
 	dac->regs = ioremap(regs->start, regs->end - regs->start + 1);
 	if (!dac->regs)
@@ -658,6 +669,8 @@ out_free_dac:
 	kfree(dac);
 out_disable_clk:
 	clk_disable(mck);
+	clk_put(sample_clk);
+out_put_mck:
 	clk_put(mck);
 	return ret;
 }
@@ -673,6 +686,7 @@ static int __devexit at32dac_remove(stru
 		free_irq(platform_get_irq(pdev, 0), dac);
 		iounmap(dac->regs);
 		clk_disable(dac->mck);
+		clk_put(dac->sample_clk);
 		clk_put(dac->mck);
 		kfree(dac);
 		platform_set_drvdata(pdev, NULL);