@@ -180,6 +180,9 @@
// compatible = "fsl,mpc5200-psc-ac97";
// cell-index = <1>;
// reg = <0x2200 0x100>;
+ // gpios = <&gpio 7 0 /* AC97_1_RES */
+ // &gpio_simple 29 0 /* AC97_1_SYNC */
+ // &gpio_simple 31 0>; /* AC97_1_SDATA_OUT */
// interrupts = <2 2 0>;
//};
@@ -184,6 +184,9 @@
// compatible = "fsl,mpc5200b-psc-ac97","fsl,mpc5200-psc-ac97";
// cell-index = <1>;
// reg = <0x2200 0x100>;
+ // gpios = <&gpio 7 0 /* AC97_1_RES */
+ // &gpio_simple 29 0 /* AC97_1_SYNC */
+ // &gpio_simple 31 0>; /* AC97_1_SDATA_OUT */
// interrupts = <2 2 0>;
//};
@@ -189,6 +189,9 @@
compatible = "mpc5200b-psc-ac97","fsl,mpc5200b-psc-ac97";
cell-index = <0>;
reg = <0x2000 0x100>;
+ gpios = <&gpio 7 0 /* AC97_1_RES */
+ &gpio_simple 29 0 /* AC97_1_SYNC */
+ &gpio_simple 31 0>; /* AC97_1_SDATA_OUT */
interrupts = <2 1 0>;
};
@@ -189,6 +189,9 @@
compatible = "fsl,mpc5200b-psc-ac97","fsl,mpc5200-psc-ac97";
cell-index = <0>;
reg = <0x2000 0x100>;
+ gpios = <&gpio 7 0 /* AC97_1_RES */
+ &gpio_simple 29 0 /* AC97_1_SYNC */
+ &gpio_simple 31 0>; /* AC97_1_SDATA_OUT */
interrupts = <2 1 0>;
};
@@ -61,6 +61,11 @@ struct psc_dma {
int id;
unsigned int slots;
+ /* gpio pins locations for cold reset */
+ int reset_gpio;
+ int sync_gpio;
+ int out_gpio;
+
/* per-stream data */
struct psc_dma_stream playback;
struct psc_dma_stream capture;
@@ -9,8 +9,10 @@
* published by the Free Software Foundation.
*/
+#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/of_device.h>
+#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#include <linux/delay.h>
@@ -20,12 +22,17 @@
#include <asm/time.h>
#include <asm/delay.h>
+#include <asm/mpc52xx.h>
#include <asm/mpc52xx_psc.h>
#include "mpc5200_dma.h"
#include "mpc5200_psc_ac97.h"
#define DRV_NAME "mpc5200-psc-ac97"
+#define MPC52xx_GPIO_PSC1_MASK 0x7
+#define MPC52xx_GPIO_PSC2_MASK (0x7<<4)
+#define MPC52xx_AC97_PSC1 0x2
+#define MPC52xx_AC97_PSC2 (0x2<<4)
/* ALSA only supports a single AC97 device so static is recommend here */
static struct psc_dma *psc_dma;
@@ -100,19 +107,69 @@ static void psc_ac97_warm_reset(struct snd_ac97 *ac97)
{
struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
+ mutex_lock(&psc_dma->mutex);
+
out_be32(®s->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_AWR);
udelay(3);
out_be32(®s->sicr, psc_dma->sicr);
+
+ mutex_unlock(&psc_dma->mutex);
}
static void psc_ac97_cold_reset(struct snd_ac97 *ac97)
{
struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
+ u32 gpio_mux;
+
+ mutex_lock(&psc_dma->mutex);
+
+ /* Reconfigure pin-muxing to gpio */
+ switch (psc_dma->id) {
+ case 0:
+ gpio_mux = MPC52xx_GPIO_PSC1_MASK; break;
+ case 1:
+ gpio_mux = MPC52xx_GPIO_PSC2_MASK; break;
+ default:
+ dev_err(psc_dma->dev,
+ "Unable to determine PSC, no cold-reset will be "
+ "performed\n");
+ return;
+ }
+
+ dev_err(psc_dma->dev, "cold reset\n");
+ mpc52xx_write_port_config(~gpio_mux, 1);
+
+ /* Assert cold reset */
+ gpio_direction_output(psc_dma->sync_gpio, 0);
+ gpio_direction_output(psc_dma->out_gpio, 0);
+ gpio_direction_output(psc_dma->reset_gpio, 0);
+
+ /* Notify the PSC that a cold reset is occurring */
+ out_be32(®s->sicr, 0);
+ udelay(2);
+
+ /* Deassert reset */
+ gpio_direction_output(psc_dma->reset_gpio, 1);
+ msleep(1);
+
+ /* Restore pin-muxing */
+ switch (psc_dma->id) {
+ case 0:
+ gpio_mux = MPC52xx_AC97_PSC1; break;
+ case 1:
+ gpio_mux = MPC52xx_AC97_PSC2; break;
+ default:
+ return;
+ }
+
+ mpc52xx_write_port_config(gpio_mux, 0);
+
+ /* Restore the serial interface mode to AC97 */
+ out_be32(®s->sicr, psc_dma->sicr);
+ out_8(®s->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
+
+ mutex_unlock(&psc_dma->mutex);
- /* Do a cold reset */
- out_8(®s->op1, MPC52xx_PSC_OP_RES);
- udelay(10);
- out_8(®s->op0, MPC52xx_PSC_OP_RES);
msleep(1);
psc_ac97_warm_reset(ac97);
}
@@ -287,6 +344,24 @@ static int __devinit psc_ac97_of_probe(struct of_device *op,
regs = psc_dma->psc_regs;
ac97.private_data = psc_dma;
+ psc_dma->reset_gpio = of_get_gpio_flags(op->node, 0, NULL);
+ psc_dma->sync_gpio = of_get_gpio_flags(op->node, 1, NULL);
+ psc_dma->out_gpio = of_get_gpio_flags(op->node, 2, NULL);
+ if ((psc_dma->reset_gpio < 0) ||
+ (psc_dma->sync_gpio < 0) ||
+ (psc_dma->out_gpio < 0)) {
+ dev_err(&op->dev, "error: cannot get GPIO pins; "
+ "reset=%i sync=%i out=%i\n",
+ psc_dma->reset_gpio,
+ psc_dma->sync_gpio,
+ psc_dma->out_gpio);
+ return -ENODEV;
+ }
+
+ gpio_request(psc_dma->reset_gpio, "psc_dma-reset");
+ gpio_request(psc_dma->sync_gpio, "psc_dma-sync");
+ gpio_request(psc_dma->out_gpio, "psc_dma-out");
+
for (i = 0; i < ARRAY_SIZE(psc_ac97_dai); i++)
psc_ac97_dai[i].private_data = psc_dma;
The implementation of the ac97 "cold" reset is flawed. If the sync and output lines are high when reset is asserted the attached ac97 device may go into test mode. Avoid this by reconfiguring the psc to gpio mode and generating the reset manually. Signed-off-by: Eric Millbrandt <emillbrandt@dekaresearch.com> --- arch/powerpc/boot/dts/lite5200.dts | 3 + arch/powerpc/boot/dts/lite5200b.dts | 3 + arch/powerpc/boot/dts/pcm030.dts | 3 + arch/powerpc/boot/dts/pcm032.dts | 3 + sound/soc/fsl/mpc5200_dma.h | 5 ++ sound/soc/fsl/mpc5200_psc_ac97.c | 83 +++++++++++++++++++++++++++++++++-- 6 files changed, 96 insertions(+), 4 deletions(-) -- 1.6.3.1 This e-mail and the information, including any attachments, it contains are intended to be a confidential communication only to the person or entity to whom it is addressed and may contain information that is privileged. If the reader of this message is not the intended recipient, you are hereby notified that any dissemination, distribution or copying of this communication is strictly prohibited. If you have received this communication in error, please immediately notify the sender and destroy the original message. Thank you. Please consider the environment before printing this email.