From df4bd0697d2925266df6af52c1247bf60a854db4 Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Thu, 8 May 2008 08:03:08 +0000 Subject: Gigabeat S: Add ATA/IDE power management. Fix parameter order of regmod32 as it was intended (had some things mixed up :P). git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17409 a1c6a512-1295-4272-9138-f99709370657 --- firmware/target/arm/imx31/gigabeat-s/ata-imx31.c | 33 ++++++++++++++++++---- firmware/target/arm/imx31/gigabeat-s/power-imx31.c | 17 ++++++++++- .../target/arm/imx31/gigabeat-s/system-imx31.c | 2 +- .../target/arm/imx31/gigabeat-s/wmcodec-imx31.c | 10 ++++--- 4 files changed, 50 insertions(+), 12 deletions(-) diff --git a/firmware/target/arm/imx31/gigabeat-s/ata-imx31.c b/firmware/target/arm/imx31/gigabeat-s/ata-imx31.c index 9c3c72e2c5..885e7e7521 100644 --- a/firmware/target/arm/imx31/gigabeat-s/ata-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/ata-imx31.c @@ -26,6 +26,7 @@ #include "ata.h" #include "ata-target.h" #include "clkctl-imx31.h" +# static const struct ata_pio_timings { @@ -81,10 +82,15 @@ static const struct ata_pio_timings static int pio_mode = 0; /* Setup mode 0 by default */ +static void ata_wait_for_idle(void) +{ + while (!(ATA_INTERRUPT_PENDING & ATA_CONTROLLER_IDLE)); +} + /* Setup the timing for PIO mode */ void ata_set_pio_timings(int mode) { - while (!(ATA_INTERRUPT_PENDING & ATA_CONTROLLER_IDLE)); + ata_wait_for_idle(); const struct ata_pio_timings * const timings = &pio_timings[mode]; /* T = period in nanoseconds */ @@ -107,20 +113,34 @@ void ata_set_pio_timings(int mode) void ata_reset(void) { /* Be sure we're not busy */ - while (!(ATA_INTERRUPT_PENDING & ATA_CONTROLLER_IDLE)); + ata_wait_for_idle(); ATA_INTF_CONTROL &= ~ATA_ATA_RST; sleep(1); ATA_INTF_CONTROL |= ATA_ATA_RST; sleep(1); - while (!(ATA_INTERRUPT_PENDING & ATA_CONTROLLER_IDLE)); + ata_wait_for_idle(); } -/* This function is called before enabling the USB bus */ void ata_enable(bool on) { - (void)on; + /* Unconditionally clock module before writing regs */ + imx31_clkctl_module_clock_gating(CG_ATA, CGM_ON_ALL); + + if (on) + { + ATA_INTF_CONTROL |= ATA_ATA_RST; + } + else + { + ata_wait_for_idle(); + + ATA_INTF_CONTROL &= ~ATA_ATA_RST; + + /* Disable off - unclock ATA module */ + imx31_clkctl_module_clock_gating(CG_ATA, CGM_OFF); + } } bool ata_is_coldstart(void) @@ -130,7 +150,8 @@ bool ata_is_coldstart(void) void ata_device_init(void) { - ATA_INTF_CONTROL |= ATA_ATA_RST; /* Make sure we're not in reset mode */ + /* Make sure we're not in reset mode */ + ata_enable(true); /* mode may be switched later once identify info is ready in which * case the main driver calls back */ diff --git a/firmware/target/arm/imx31/gigabeat-s/power-imx31.c b/firmware/target/arm/imx31/gigabeat-s/power-imx31.c index e51318d16f..3e845d7d93 100644 --- a/firmware/target/arm/imx31/gigabeat-s/power-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/power-imx31.c @@ -19,6 +19,7 @@ #include "config.h" #include "system.h" #include "power.h" +#include "ata.h" #include "backlight.h" #include "backlight-target.h" #include "avic-imx31.h" @@ -50,7 +51,21 @@ bool charging_state(void) { void ide_power_enable(bool on) { - (void)on; + if (!on) + { + /* Bus must be isolated before power off */ + imx31_regmod32(&GPIO2_DR, (1 << 16), (1 << 16)); + } + + /* HD power switch */ + imx31_regmod32(&GPIO3_DR, on ? (1 << 5) : 0, (1 << 5)); + + if (on) + { + /* Bus switch may be turned on after powerup */ + sleep(HZ/10); + imx31_regmod32(&GPIO2_DR, 0, (1 << 16)); + } } bool ide_powered(void) diff --git a/firmware/target/arm/imx31/gigabeat-s/system-imx31.c b/firmware/target/arm/imx31/gigabeat-s/system-imx31.c index ca82a18fbd..412bbcc4b0 100644 --- a/firmware/target/arm/imx31/gigabeat-s/system-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/system-imx31.c @@ -27,7 +27,7 @@ void system_init(void) gpio_init(); } -void imx31_regmod32(volatile uint32_t *reg_p, uint32_t mask, uint32_t value) +void imx31_regmod32(volatile uint32_t *reg_p, uint32_t value, uint32_t mask) { value &= mask; mask = ~mask; diff --git a/firmware/target/arm/imx31/gigabeat-s/wmcodec-imx31.c b/firmware/target/arm/imx31/gigabeat-s/wmcodec-imx31.c index c8a04ce20e..a88571ee14 100644 --- a/firmware/target/arm/imx31/gigabeat-s/wmcodec-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/wmcodec-imx31.c @@ -39,10 +39,12 @@ static struct i2c_node wm8978_i2c_node = void audiohw_init(void) { /* USB PLL = 338.688MHz, /30 = 11.2896MHz = 256Fs */ - imx31_regmod32(&CLKCTL_PDR1, PDR1_SSI1_PODF | PDR1_SSI2_PODF, - PDR1_SSI1_PODFw(64-1) | PDR1_SSI2_PODFw(5-1)); - imx31_regmod32(&CLKCTL_PDR1, PDR1_SSI1_PRE_PODF | PDR1_SSI2_PRE_PODF, - PDR1_SSI1_PRE_PODFw(4-1) | PDR1_SSI2_PRE_PODFw(1-1)); + imx31_regmod32(&CLKCTL_PDR1, + PDR1_SSI1_PODFw(64-1) | PDR1_SSI2_PODFw(5-1), + PDR1_SSI1_PODF | PDR1_SSI2_PODF); + imx31_regmod32(&CLKCTL_PDR1, + PDR1_SSI1_PRE_PODFw(4-1) | PDR1_SSI2_PRE_PODFw(1-1), + PDR1_SSI1_PRE_PODF | PDR1_SSI2_PRE_PODF); i2c_enable_node(&wm8978_i2c_node, true); audiohw_preinit(); -- cgit v1.2.3