|
@@ -1039,7 +1039,7 @@ static int azx_alloc_cmd_io(struct azx *chip)
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(azx_alloc_cmd_io);
|
|
|
|
|
|
-void azx_init_cmd_io(struct azx *chip)
|
|
|
+static void azx_init_cmd_io(struct azx *chip)
|
|
|
{
|
|
|
int timeout;
|
|
|
|
|
@@ -1102,7 +1102,7 @@ void azx_init_cmd_io(struct azx *chip)
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(azx_init_cmd_io);
|
|
|
|
|
|
-void azx_free_cmd_io(struct azx *chip)
|
|
|
+static void azx_free_cmd_io(struct azx *chip)
|
|
|
{
|
|
|
spin_lock_irq(&chip->reg_lock);
|
|
|
/* disable ringbuffer DMAs */
|
|
@@ -1574,5 +1574,178 @@ void azx_free_stream_pages(struct azx *chip)
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(azx_free_stream_pages);
|
|
|
|
|
|
+/*
|
|
|
+ * Lowlevel interface
|
|
|
+ */
|
|
|
+
|
|
|
+/* enter link reset */
|
|
|
+void azx_enter_link_reset(struct azx *chip)
|
|
|
+{
|
|
|
+ unsigned long timeout;
|
|
|
+
|
|
|
+ /* reset controller */
|
|
|
+ azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_RESET);
|
|
|
+
|
|
|
+ timeout = jiffies + msecs_to_jiffies(100);
|
|
|
+ while ((azx_readb(chip, GCTL) & ICH6_GCTL_RESET) &&
|
|
|
+ time_before(jiffies, timeout))
|
|
|
+ usleep_range(500, 1000);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(azx_enter_link_reset);
|
|
|
+
|
|
|
+/* exit link reset */
|
|
|
+static void azx_exit_link_reset(struct azx *chip)
|
|
|
+{
|
|
|
+ unsigned long timeout;
|
|
|
+
|
|
|
+ azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | ICH6_GCTL_RESET);
|
|
|
+
|
|
|
+ timeout = jiffies + msecs_to_jiffies(100);
|
|
|
+ while (!azx_readb(chip, GCTL) &&
|
|
|
+ time_before(jiffies, timeout))
|
|
|
+ usleep_range(500, 1000);
|
|
|
+}
|
|
|
+
|
|
|
+/* reset codec link */
|
|
|
+static int azx_reset(struct azx *chip, int full_reset)
|
|
|
+{
|
|
|
+ if (!full_reset)
|
|
|
+ goto __skip;
|
|
|
+
|
|
|
+ /* clear STATESTS */
|
|
|
+ azx_writew(chip, STATESTS, STATESTS_INT_MASK);
|
|
|
+
|
|
|
+ /* reset controller */
|
|
|
+ azx_enter_link_reset(chip);
|
|
|
+
|
|
|
+ /* delay for >= 100us for codec PLL to settle per spec
|
|
|
+ * Rev 0.9 section 5.5.1
|
|
|
+ */
|
|
|
+ usleep_range(500, 1000);
|
|
|
+
|
|
|
+ /* Bring controller out of reset */
|
|
|
+ azx_exit_link_reset(chip);
|
|
|
+
|
|
|
+ /* Brent Chartrand said to wait >= 540us for codecs to initialize */
|
|
|
+ usleep_range(1000, 1200);
|
|
|
+
|
|
|
+ __skip:
|
|
|
+ /* check to see if controller is ready */
|
|
|
+ if (!azx_readb(chip, GCTL)) {
|
|
|
+ dev_dbg(chip->card->dev, "azx_reset: controller not ready!\n");
|
|
|
+ return -EBUSY;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Accept unsolicited responses */
|
|
|
+ if (!chip->single_cmd)
|
|
|
+ azx_writel(chip, GCTL, azx_readl(chip, GCTL) |
|
|
|
+ ICH6_GCTL_UNSOL);
|
|
|
+
|
|
|
+ /* detect codecs */
|
|
|
+ if (!chip->codec_mask) {
|
|
|
+ chip->codec_mask = azx_readw(chip, STATESTS);
|
|
|
+ dev_dbg(chip->card->dev, "codec_mask = 0x%x\n",
|
|
|
+ chip->codec_mask);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* enable interrupts */
|
|
|
+static void azx_int_enable(struct azx *chip)
|
|
|
+{
|
|
|
+ /* enable controller CIE and GIE */
|
|
|
+ azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) |
|
|
|
+ ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN);
|
|
|
+}
|
|
|
+
|
|
|
+/* disable interrupts */
|
|
|
+static void azx_int_disable(struct azx *chip)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ /* disable interrupts in stream descriptor */
|
|
|
+ for (i = 0; i < chip->num_streams; i++) {
|
|
|
+ struct azx_dev *azx_dev = &chip->azx_dev[i];
|
|
|
+ azx_sd_writeb(chip, azx_dev, SD_CTL,
|
|
|
+ azx_sd_readb(chip, azx_dev, SD_CTL) &
|
|
|
+ ~SD_INT_MASK);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* disable SIE for all streams */
|
|
|
+ azx_writeb(chip, INTCTL, 0);
|
|
|
+
|
|
|
+ /* disable controller CIE and GIE */
|
|
|
+ azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) &
|
|
|
+ ~(ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN));
|
|
|
+}
|
|
|
+
|
|
|
+/* clear interrupts */
|
|
|
+static void azx_int_clear(struct azx *chip)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ /* clear stream status */
|
|
|
+ for (i = 0; i < chip->num_streams; i++) {
|
|
|
+ struct azx_dev *azx_dev = &chip->azx_dev[i];
|
|
|
+ azx_sd_writeb(chip, azx_dev, SD_STS, SD_INT_MASK);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* clear STATESTS */
|
|
|
+ azx_writew(chip, STATESTS, STATESTS_INT_MASK);
|
|
|
+
|
|
|
+ /* clear rirb status */
|
|
|
+ azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
|
|
|
+
|
|
|
+ /* clear int status */
|
|
|
+ azx_writel(chip, INTSTS, ICH6_INT_CTRL_EN | ICH6_INT_ALL_STREAM);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * reset and start the controller registers
|
|
|
+ */
|
|
|
+void azx_init_chip(struct azx *chip, int full_reset)
|
|
|
+{
|
|
|
+ if (chip->initialized)
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* reset controller */
|
|
|
+ azx_reset(chip, full_reset);
|
|
|
+
|
|
|
+ /* initialize interrupts */
|
|
|
+ azx_int_clear(chip);
|
|
|
+ azx_int_enable(chip);
|
|
|
+
|
|
|
+ /* initialize the codec command I/O */
|
|
|
+ if (!chip->single_cmd)
|
|
|
+ azx_init_cmd_io(chip);
|
|
|
+
|
|
|
+ /* program the position buffer */
|
|
|
+ azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr);
|
|
|
+ azx_writel(chip, DPUBASE, upper_32_bits(chip->posbuf.addr));
|
|
|
+
|
|
|
+ chip->initialized = 1;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(azx_init_chip);
|
|
|
+
|
|
|
+void azx_stop_chip(struct azx *chip)
|
|
|
+{
|
|
|
+ if (!chip->initialized)
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* disable interrupts */
|
|
|
+ azx_int_disable(chip);
|
|
|
+ azx_int_clear(chip);
|
|
|
+
|
|
|
+ /* disable CORB/RIRB */
|
|
|
+ azx_free_cmd_io(chip);
|
|
|
+
|
|
|
+ /* disable position buffer */
|
|
|
+ azx_writel(chip, DPLBASE, 0);
|
|
|
+ azx_writel(chip, DPUBASE, 0);
|
|
|
+
|
|
|
+ chip->initialized = 0;
|
|
|
+}
|
|
|
+
|
|
|
MODULE_LICENSE("GPL");
|
|
|
MODULE_DESCRIPTION("Common HDA driver funcitons");
|