forked from len0rd/rockbox
Serial driver for imx31. Perhaps not 100% but maybe 80-90% (future developments will tell). Factor-out the mc13783 stuff and make that driver a layer above the SPI. TODO: start processing PMIC interrupts. Start a clkctl API for imx31 (we'll see if this sticks around but it seems reasonable here). Misc. stuff for convenience/neatness.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17070 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
f46a7533a4
commit
0b1d7e76d7
13 changed files with 858 additions and 87 deletions
|
|
@ -647,11 +647,13 @@ target/arm/imx31/gigabeat-s/ata-imx31.c
|
|||
target/arm/imx31/gigabeat-s/avic-imx31.c
|
||||
target/arm/imx31/gigabeat-s/backlight-imx31.c
|
||||
target/arm/imx31/gigabeat-s/button-imx31.c
|
||||
target/arm/imx31/gigabeat-s/clkctl-imx31.c
|
||||
target/arm/imx31/gigabeat-s/dma_start.c
|
||||
target/arm/imx31/gigabeat-s/kernel-imx31.c
|
||||
target/arm/imx31/gigabeat-s/i2c-imx31.c
|
||||
target/arm/imx31/gigabeat-s/i2s-imx31.c
|
||||
target/arm/imx31/gigabeat-s/lcd-imx31.c
|
||||
target/arm/imx31/gigabeat-s/mc13783-imx31.c
|
||||
target/arm/imx31/gigabeat-s/mmu-imx31.c
|
||||
target/arm/imx31/gigabeat-s/power-imx31.c
|
||||
target/arm/imx31/gigabeat-s/powermgmt-imx31.c
|
||||
|
|
|
|||
|
|
@ -83,6 +83,9 @@
|
|||
/* Define this if you want to use coldfire's i2c interface */
|
||||
#define CONFIG_I2C I2C_IMX31L
|
||||
|
||||
/* Define the bitmask of serial interface modules (CSPI) used */
|
||||
#define SPI_MODULE_MASK (USE_CSPI2_MODULE)
|
||||
|
||||
/* Type of mobile power - check this out */
|
||||
#define BATTERY_CAPACITY_DEFAULT 2000 /* default battery capacity */
|
||||
#define BATTERY_CAPACITY_MIN 1500 /* min. capacity selectable */
|
||||
|
|
|
|||
|
|
@ -516,32 +516,41 @@
|
|||
#define GPIO3_ISR (*(REG32_PTR_T)(GPIO3_BASE_ADDR+0x18))
|
||||
|
||||
/* CSPI */
|
||||
#define CSPI_RXDATA1 (*(REG32_PTR_T)(CSPI1_BASE_ADDR+0x00))
|
||||
#define CSPI_TXDATA1 (*(REG32_PTR_T)(CSPI1_BASE_ADDR+0x04))
|
||||
#define CSPI_CONREG1 (*(REG32_PTR_T)(CSPI1_BASE_ADDR+0x08))
|
||||
#define CSPI_INTREG1 (*(REG32_PTR_T)(CSPI1_BASE_ADDR+0x0C))
|
||||
#define CSPI_DMAREG1 (*(REG32_PTR_T)(CSPI1_BASE_ADDR+0x10))
|
||||
#define CSPI_STATREG1 (*(REG32_PTR_T)(CSPI1_BASE_ADDR+0x14))
|
||||
#define CSPI_PERIODREG1 (*(REG32_PTR_T)(CSPI1_BASE_ADDR+0x18))
|
||||
#define CSPI_TESTREG1 (*(REG32_PTR_T)(CSPI1_BASE_ADDR+0x1C0))
|
||||
#define CSPI_RXDATA_I 0x00 /* Offset - 0x00 */
|
||||
#define CSPI_TXDATA_I 0x01 /* Offset - 0x04 */
|
||||
#define CSPI_CONREG_I 0x02 /* Offset - 0x08 */
|
||||
#define CSPI_INTREG_I 0x03 /* Offset - 0x0C */
|
||||
#define CSPI_DMAREG_I 0x04 /* Offset - 0x10 */
|
||||
#define CSPI_STATREG_I 0x05 /* Offset - 0x14 */
|
||||
#define CSPI_PERIODREG_I 0x06 /* Offset - 0x18 */
|
||||
#define CSPI_TESTREG_I 0x70 /* Offset - 0x1C0 */
|
||||
|
||||
#define CSPI_RXDATA2 (*(REG32_PTR_T)(CSPI2_BASE_ADDR+0x00))
|
||||
#define CSPI_TXDATA2 (*(REG32_PTR_T)(CSPI2_BASE_ADDR+0x04))
|
||||
#define CSPI_CONREG2 (*(REG32_PTR_T)(CSPI2_BASE_ADDR+0x08))
|
||||
#define CSPI_INTREG2 (*(REG32_PTR_T)(CSPI2_BASE_ADDR+0x0C))
|
||||
#define CSPI_DMAREG2 (*(REG32_PTR_T)(CSPI2_BASE_ADDR+0x10))
|
||||
#define CSPI_STATREG2 (*(REG32_PTR_T)(CSPI2_BASE_ADDR+0x14))
|
||||
#define CSPI_PERIODREG2 (*(REG32_PTR_T)(CSPI2_BASE_ADDR+0x18))
|
||||
#define CSPI_TESTREG2 (*(REG32_PTR_T)(CSPI2_BASE_ADDR+0x1C0))
|
||||
#define CSPI_RXDATA1 (((REG32_PTR_T)CSPI1_BASE_ADDR)[CSPI_RXDATA_I])
|
||||
#define CSPI_TXDATA1 (((REG32_PTR_T)CSPI1_BASE_ADDR)[CSPI_TXDATA_I])
|
||||
#define CSPI_CONREG1 (((REG32_PTR_T)CSPI1_BASE_ADDR)[CSPI_CONREG_I])
|
||||
#define CSPI_INTREG1 (((REG32_PTR_T)CSPI1_BASE_ADDR)[CSPI_INTREG_I])
|
||||
#define CSPI_DMAREG1 (((REG32_PTR_T)CSPI1_BASE_ADDR)[CSPI_DMAREG_I])
|
||||
#define CSPI_STATREG1 (((REG32_PTR_T)CSPI1_BASE_ADDR)[CSPI_STATREG_I])
|
||||
#define CSPI_PERIODREG1 (((REG32_PTR_T)CSPI1_BASE_ADDR)[CSPI_PERIODREG_I])
|
||||
#define CSPI_TESTREG1 (((REG32_PTR_T)CSPI1_BASE_ADDR)[CSPI_TESTREG_I])
|
||||
|
||||
#define CSPI_RXDATA3 (*(REG32_PTR_T)(CSPI3_BASE_ADDR+0x00))
|
||||
#define CSPI_TXDATA3 (*(REG32_PTR_T)(CSPI3_BASE_ADDR+0x04))
|
||||
#define CSPI_CONREG3 (*(REG32_PTR_T)(CSPI3_BASE_ADDR+0x08))
|
||||
#define CSPI_INTREG3 (*(REG32_PTR_T)(CSPI3_BASE_ADDR+0x0C))
|
||||
#define CSPI_DMAREG3 (*(REG32_PTR_T)(CSPI3_BASE_ADDR+0x10))
|
||||
#define CSPI_STATREG3 (*(REG32_PTR_T)(CSPI3_BASE_ADDR+0x14))
|
||||
#define CSPI_PERIODREG3 (*(REG32_PTR_T)(CSPI3_BASE_ADDR+0x18))
|
||||
#define CSPI_TESTREG3 (*(REG32_PTR_T)(CSPI3_BASE_ADDR+0x1C0))
|
||||
#define CSPI_RXDATA2 (((REG32_PTR_T)CSPI2_BASE_ADDR)[CSPI_RXDATA_I])
|
||||
#define CSPI_TXDATA2 (((REG32_PTR_T)CSPI2_BASE_ADDR)[CSPI_TXDATA_I])
|
||||
#define CSPI_CONREG2 (((REG32_PTR_T)CSPI2_BASE_ADDR)[CSPI_CONREG_I])
|
||||
#define CSPI_INTREG2 (((REG32_PTR_T)CSPI2_BASE_ADDR)[CSPI_INTREG_I])
|
||||
#define CSPI_DMAREG2 (((REG32_PTR_T)CSPI2_BASE_ADDR)[CSPI_DMAREG_I])
|
||||
#define CSPI_STATREG2 (((REG32_PTR_T)CSPI2_BASE_ADDR)[CSPI_STATREG_I])
|
||||
#define CSPI_PERIODREG2 (((REG32_PTR_T)CSPI2_BASE_ADDR)[CSPI_PERIODREG_I])
|
||||
#define CSPI_TESTREG2 (((REG32_PTR_T)CSPI2_BASE_ADDR)[CSPI_TESTREG_I])
|
||||
|
||||
#define CSPI_RXDATA3 (((REG32_PTR_T)CSPI3_BASE_ADDR)[CSPI_RXDATA_I])
|
||||
#define CSPI_TXDATA3 (((REG32_PTR_T)CSPI3_BASE_ADDR)[CSPI_TXDATA_I])
|
||||
#define CSPI_CONREG3 (((REG32_PTR_T)CSPI3_BASE_ADDR)[CSPI_CONREG_I])
|
||||
#define CSPI_INTREG3 (((REG32_PTR_T)CSPI3_BASE_ADDR)[CSPI_INTREG_I])
|
||||
#define CSPI_DMAREG3 (((REG32_PTR_T)CSPI3_BASE_ADDR)[CSPI_DMAREG_I])
|
||||
#define CSPI_STATREG3 (((REG32_PTR_T)CSPI3_BASE_ADDR)[CSPI_STATREG_I])
|
||||
#define CSPI_PERIODREG3 (((REG32_PTR_T)CSPI3_BASE_ADDR)[CSPI_PERIODREG_I])
|
||||
#define CSPI_TESTREG3 (((REG32_PTR_T)CSPI3_BASE_ADDR)[CSPI_TESTREG_I])
|
||||
|
||||
/* CSPI CONREG flags/fields */
|
||||
#define CSPI_CONREG_CHIP_SELECT_SS0 (0 << 24)
|
||||
|
|
@ -563,6 +572,7 @@
|
|||
#define CSPI_CONREG_DATA_RATE_DIV_256 (6 << 16)
|
||||
#define CSPI_CONREG_DATA_RATE_DIV_512 (7 << 16)
|
||||
#define CSPI_CONREG_DATA_RATE_DIV_MASK (7 << 16)
|
||||
#define CSPI_BITCOUNT(n) ((n) << 8)
|
||||
#define CSPI_CONREG_SSPOL (1 << 7)
|
||||
#define CSPI_CONREG_SSCTL (1 << 6)
|
||||
#define CSPI_CONREG_PHA (1 << 6)
|
||||
|
|
@ -581,7 +591,7 @@
|
|||
#define CSPI_INTREG_RREN (1 << 3)
|
||||
#define CSPI_INTREG_TFEN (1 << 2)
|
||||
#define CSPI_INTREG_THEN (1 << 1)
|
||||
#define CSPI_INTREF_TEEN (1 << 0)
|
||||
#define CSPI_INTREG_TEEN (1 << 0)
|
||||
|
||||
/* CSPI DMAREG flags */
|
||||
#define CSPI_DMAREG_RFDEN (1 << 5)
|
||||
|
|
@ -764,12 +774,6 @@
|
|||
#define CLKCTL_PMCR1 (*(REG32_PTR_T)(CCM_BASE_ADDR+0x60))
|
||||
#define CLKCTL_PDR2 (*(REG32_PTR_T)(CCM_BASE_ADDR+0x64))
|
||||
|
||||
#define CG_OFF 0x0 /* Always off */
|
||||
#define CG_ON_RUN 0x1 /* On in run mode, off in wait and doze */
|
||||
#define CG_ON_RUN_WAIT 0x2 /* On in run and wait modes, off in doze */
|
||||
#define CG_ON_ALL 0x3 /* Always on */
|
||||
#define CG_MASK 0x3 /* bitmask */
|
||||
|
||||
#define CGR0_SD_MMC1(cg) ((cg) << 0*2)
|
||||
#define CGR0_SD_MMC2(cg) ((cg) << 1*2)
|
||||
#define CGR0_GPT(cg) ((cg) << 2*2)
|
||||
|
|
@ -812,6 +816,39 @@
|
|||
#define CGR2_RTIC(cg) ((cg) << 5*2)
|
||||
#define CGR2_FIR(cg) ((cg) << 6*2)
|
||||
|
||||
#define WIM_GPIO3 (1 << 0)
|
||||
#define WIM_GPIO2 (1 << 1)
|
||||
#define WIM_GPIO1 (1 << 2)
|
||||
#define WIM_PCMCIA (1 << 3)
|
||||
#define WIM_WDT (1 << 4)
|
||||
#define WIM_USB_OTG (1 << 5)
|
||||
#define WIM_IPI_INT_UH2 (1 << 6)
|
||||
#define WIM_IPI_INT_UH1 (1 << 7)
|
||||
#define WIM_IPI_INT_UART5_ANDED (1 << 8)
|
||||
#define WIM_IPI_INT_UART4_ANDED (1 << 9)
|
||||
#define WIM_IPI_INT_UART3_ANDED (1 << 10)
|
||||
#define WIM_IPI_INT_UART2_ANDED (1 << 11)
|
||||
#define WIM_IPI_INT_UART1_ANDED (1 << 12)
|
||||
#define WIM_IPI_INT_SIM_DATA_IRQ (1 << 13)
|
||||
#define WIM_IPI_INT_SDHC2 (1 << 14)
|
||||
#define WIM_IPI_INT_SDHC1 (1 << 15)
|
||||
#define WIM_IPI_INT_RTC (1 << 16)
|
||||
#define WIM_IPI_INT_PWM (1 << 17)
|
||||
#define WIM_IPI_INT_KPP (1 << 18)
|
||||
#define WIM_IPI_INT_IIM (1 << 19)
|
||||
#define WIM_IPI_INT_GPT (1 << 20)
|
||||
#define WIM_IPI_INT_FIR (1 << 21)
|
||||
#define WIM_IPI_INT_EPIT2 (1 << 22)
|
||||
#define WIM_IPI_INT_EPIT1 (1 << 23)
|
||||
#define WIM_IPI_INT_CSPI2 (1 << 24)
|
||||
#define WIM_IPI_INT_CSPI1 (1 << 25)
|
||||
#define WIM_IPI_INT_POWER_FAIL (1 << 26)
|
||||
#define WIM_IPI_INT_CSPI3 (1 << 27)
|
||||
#define WIM_RESERVED28 (1 << 28)
|
||||
#define WIM_RESERVED29 (1 << 29)
|
||||
#define WIM_RESERVED30 (1 << 30)
|
||||
#define WIM_RESERVED31 (1 << 31)
|
||||
|
||||
/* WEIM - CS0 */
|
||||
#define CSCRU 0x00
|
||||
#define CSCRL 0x04
|
||||
|
|
|
|||
99
firmware/export/mc13783.h
Normal file
99
firmware/export/mc13783.h
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2008 by Michael Sevakis
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef _MC13783_H_
|
||||
#define _MC13783_H_
|
||||
|
||||
enum mc13783_regs_enum
|
||||
{
|
||||
MC13783_INTERRUPT_STATUS0 = 0x00,
|
||||
MC13783_INTERRUPT_MASK0,
|
||||
MC13783_INTERRUPT_SENSE0,
|
||||
MC13783_INTERRUPT_STATUS1,
|
||||
MC13783_INTERRUPT_MASK1,
|
||||
MC13783_INTERRUPT_SENSE1,
|
||||
MC13783_POWER_UP_MODE_SENSE,
|
||||
MC13783_IDENTIFICATION,
|
||||
MC13783_SEMAPHORE,
|
||||
MC13783_ARBITRATION_PERIPHERAL_AUDIO,
|
||||
MC13783_ARBITRATION_SWITCHERS,
|
||||
MC13783_ARBITRATION_REGULATORS0,
|
||||
MC13783_ARBITRATION_REGULATORS1,
|
||||
MC13783_POWER_CONTROL0,
|
||||
MC13783_POWER_CONTROL1,
|
||||
MC13783_POWER_CONTROL2,
|
||||
MC13783_REGEN_ASSIGNMENT,
|
||||
MC13783_CONTROL_SPARE,
|
||||
MC13783_MEMORYA,
|
||||
MC13783_MEMORYB,
|
||||
MC13783_RTC_TIME,
|
||||
MC13783_RTC_ALARM,
|
||||
MC13783_RTC_DAY,
|
||||
MC13783_RTC_DAY_ALARM,
|
||||
MC13783_SWITCHERS0,
|
||||
MC13783_SWITCHERS1,
|
||||
MC13783_SWITCHERS2,
|
||||
MC13783_SWITCHERS3,
|
||||
MC13783_SWITCHERS4,
|
||||
MC13783_SWITCHERS5,
|
||||
MC13783_REGULATOR_SETTING0,
|
||||
MC13783_REGULATOR_SETTING1,
|
||||
MC13783_REGULATOR_MODE0,
|
||||
MC13783_REGULATOR_MODE1,
|
||||
MC13783_POWER_MISCELLANEOUS,
|
||||
MC13783_POWER_SPARE,
|
||||
MC13783_AUDIO_RX0,
|
||||
MC13783_AUDIO_RX1,
|
||||
MC13783_AUDIO_TX,
|
||||
MC13783_SSI_NETWORK,
|
||||
MC13783_AUDIO_CODEC,
|
||||
MC13783_AUDIO_STEREO_CODEC,
|
||||
MC13783_AUDIO_SPARE,
|
||||
MC13783_ADC0,
|
||||
MC13783_ADC1,
|
||||
MC13783_ADC2,
|
||||
MC13783_ADC3,
|
||||
MC13783_ADC4,
|
||||
MC13783_CHARGER,
|
||||
MC13783_USB0,
|
||||
MC13783_CHARGER_USB1,
|
||||
MC13783_LED_CONTROL0,
|
||||
MC13783_LED_CONTROL1,
|
||||
MC13783_LED_CONTROL2,
|
||||
MC13783_LED_CONTROL3,
|
||||
MC13783_LED_CONTROL4,
|
||||
MC13783_LED_CONTROL5,
|
||||
MC13783_SPARE,
|
||||
MC13783_TRIM0,
|
||||
MC13783_TRIM1,
|
||||
MC13783_TEST0,
|
||||
MC13783_TEST1,
|
||||
MC13783_TEST2,
|
||||
MC13783_TEST3,
|
||||
MC13783_NUM_REGS,
|
||||
};
|
||||
|
||||
void mc13783_init(void);
|
||||
void mc13783_set(unsigned address, uint32_t bits);
|
||||
void mc13783_clear(unsigned address, uint32_t bits);
|
||||
int mc13783_write(unsigned address, uint32_t data);
|
||||
int mc13783_write_multiple(unsigned start, const uint32_t *buffer, int count);
|
||||
uint32_t mc13783_read(unsigned address);
|
||||
int mc13783_read_multiple(unsigned start, uint32_t *buffer, int count);
|
||||
|
||||
#endif /* _MC13783_H_ */
|
||||
|
|
@ -81,6 +81,9 @@ void kernel_init(void)
|
|||
memset(&all_queues, 0, sizeof(all_queues));
|
||||
corelock_init(&all_queues.cl);
|
||||
tick_start(1000/HZ);
|
||||
#ifdef KDEV_INIT
|
||||
kernel_device_init();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
#include "backlight.h"
|
||||
#include "lcd.h"
|
||||
#include "power.h"
|
||||
#include "spi-imx31.h"
|
||||
#include "mc13783.h"
|
||||
#include "debug.h"
|
||||
|
||||
bool _backlight_init(void)
|
||||
|
|
@ -33,14 +33,14 @@ bool _backlight_init(void)
|
|||
|
||||
void _backlight_on(void)
|
||||
{
|
||||
// This relies on the SPI interface being initialised already
|
||||
spi_send(51, 1);
|
||||
/* LEDEN=1 */
|
||||
mc13783_set(MC13783_LED_CONTROL0, (1 << 0));
|
||||
}
|
||||
|
||||
void _backlight_off(void)
|
||||
{
|
||||
// This relies on the SPI interface being initialised already
|
||||
spi_send(51, 0);
|
||||
/* LEDEN=0 */
|
||||
mc13783_clear(MC13783_LED_CONTROL0, (1 << 0));
|
||||
}
|
||||
|
||||
/* Assumes that the backlight has been initialized */
|
||||
|
|
|
|||
45
firmware/target/arm/imx31/gigabeat-s/clkctl-imx31.c
Normal file
45
firmware/target/arm/imx31/gigabeat-s/clkctl-imx31.c
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2008 Michael Sevakis
|
||||
*
|
||||
* Clock control functions for IMX31 processor
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include "system.h"
|
||||
#include "cpu.h"
|
||||
#include "clkctl-imx31.h"
|
||||
|
||||
void imx31_clkctl_module_clock_gating(enum IMX31_CG_LIST cg,
|
||||
enum IMX31_CG_MODES mode)
|
||||
{
|
||||
volatile unsigned long *reg;
|
||||
unsigned long mask;
|
||||
int shift;
|
||||
int oldlevel;
|
||||
|
||||
if (cg >= CG_NUM_CLOCKS)
|
||||
return;
|
||||
|
||||
reg = &CLKCTL_CGR0 + cg / 16; /* Select CGR0, CGR1, CGR2 */
|
||||
shift = 2*(cg % 16); /* Get field shift */
|
||||
mask = CG_MASK << shift; /* Select field */
|
||||
|
||||
oldlevel = disable_interrupt_save(IRQ_FIQ_STATUS);
|
||||
|
||||
*reg = (*reg & ~mask) | ((mode << shift) & mask);
|
||||
|
||||
restore_interrupt(oldlevel);
|
||||
}
|
||||
86
firmware/target/arm/imx31/gigabeat-s/clkctl-imx31.h
Normal file
86
firmware/target/arm/imx31/gigabeat-s/clkctl-imx31.h
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2008 Michael Sevakis
|
||||
*
|
||||
* Clock control functions for IMX31 processor
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef _CLKCTL_IMX31_H_
|
||||
#define _CLKCTL_IMX31_H_
|
||||
|
||||
enum IMX31_CG_LIST
|
||||
{
|
||||
/* CGR0 */
|
||||
CG_SD_MMC1 = 0,
|
||||
CG_SD_MMC2,
|
||||
CG_GPT,
|
||||
CG_EPIT1,
|
||||
CG_EPIT2,
|
||||
CG_IIM,
|
||||
CG_ATA,
|
||||
CG_SDMA,
|
||||
CG_CSPI3,
|
||||
CG_RNG,
|
||||
CG_UART1,
|
||||
CG_UART2,
|
||||
CG_SSI1,
|
||||
CG_I2C1,
|
||||
CG_I2C2,
|
||||
CG_I2C3,
|
||||
/* CGR1 */
|
||||
CG_HANTRO,
|
||||
CG_MEMSTICK1,
|
||||
CG_MEMSTICK2,
|
||||
CG_CSI,
|
||||
CG_RTC,
|
||||
CG_WDOG,
|
||||
CG_PWM,
|
||||
CG_SIM,
|
||||
CG_ECT,
|
||||
CG_USBOTG,
|
||||
CG_KPP,
|
||||
CG_IPU,
|
||||
CG_UART3,
|
||||
CG_UART4,
|
||||
CG_UART5,
|
||||
CG_1_WIRE,
|
||||
/* CGR2 */
|
||||
CG_SSI2,
|
||||
CG_CSPI1,
|
||||
CG_CSPI2,
|
||||
CG_GACC,
|
||||
CG_EMI,
|
||||
CG_RTIC,
|
||||
CG_FIR,
|
||||
CG_NUM_CLOCKS
|
||||
};
|
||||
|
||||
enum IMX31_CG_MODES
|
||||
{
|
||||
CGM_OFF = 0x0, /* Always off */
|
||||
CGM_ON_RUN = 0x1, /* On in run mode, off in wait and doze */
|
||||
CGM_ON_RUN_WAIT = 0x2, /* On in run and wait modes, off in doze */
|
||||
CGM_ON_ALL = 0x3, /* Always on */
|
||||
};
|
||||
|
||||
#define CG_MASK 0x3 /* bitmask */
|
||||
|
||||
/* Enable or disable module clocks independently - module must _not_ be
|
||||
* active! */
|
||||
void imx31_clkctl_module_clock_gating(enum IMX31_CG_LIST cg,
|
||||
enum IMX31_CG_MODES mode);
|
||||
|
||||
#endif /* _CLKCTL_IMX31_H_ */
|
||||
|
|
@ -19,6 +19,9 @@
|
|||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "avic-imx31.h"
|
||||
#include "spi-imx31.h"
|
||||
#include "mc13783.h"
|
||||
#include "clkctl-imx31.h"
|
||||
#include "kernel.h"
|
||||
#include "thread.h"
|
||||
|
||||
|
|
@ -42,10 +45,11 @@ static __attribute__((interrupt("IRQ"))) void EPIT1_HANDLER(void)
|
|||
|
||||
void tick_start(unsigned int interval_in_ms)
|
||||
{
|
||||
CLKCTL_CGR0 |= CGR0_EPIT1(CG_ON_ALL); /* EPIT1 module clock ON -
|
||||
before writing regs! */
|
||||
imx31_clkctl_module_clock_gating(CG_EPIT1, CGM_ON_ALL); /* EPIT1 module
|
||||
clock ON - before writing
|
||||
regs! */
|
||||
EPITCR1 &= ~(EPITCR_OCIEN | EPITCR_EN); /* Disable the counter */
|
||||
CLKCTL_WIMR0 &= ~(1 << 23); /* Clear wakeup mask */
|
||||
CLKCTL_WIMR0 &= ~WIM_IPI_INT_EPIT1; /* Clear wakeup mask */
|
||||
|
||||
/* mcu_main_clk = 528MHz = 27MHz * 2 * ((9 + 7/9) / 1)
|
||||
* CLKSRC = ipg_clk = 528MHz / 4 / 2 = 66MHz,
|
||||
|
|
@ -66,11 +70,18 @@ void tick_start(unsigned int interval_in_ms)
|
|||
EPITCR1 |= EPITCR_EN; /* Enable the counter */
|
||||
}
|
||||
|
||||
void kernel_device_init(void)
|
||||
{
|
||||
spi_init();
|
||||
mc13783_init();
|
||||
}
|
||||
|
||||
#ifdef BOOTLOADER
|
||||
void tick_stop(void)
|
||||
{
|
||||
avic_disable_int(EPIT1); /* Disable insterrupt */
|
||||
EPITCR1 &= ~(EPITCR_OCIEN | EPITCR_EN); /* Disable counter */
|
||||
CLKCTL_CGR0 &= ~CGR0_EPIT1(CG_MASK); /* EPIT1 module clock OFF */
|
||||
EPITSR1 = EPITSR_OCIF; /* Clear pending */
|
||||
imx31_clkctl_module_clock_gating(CG_EPIT1, CGM_OFF); /* Turn off module clock */
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
173
firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c
Normal file
173
firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2008 by Michael Sevakis
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include "system.h"
|
||||
#include "cpu.h"
|
||||
#include "spi-imx31.h"
|
||||
#include "mc13783.h"
|
||||
#include "debug.h"
|
||||
#include "kernel.h"
|
||||
|
||||
/* This is all based on communicating with the MC13783 PMU which is on
|
||||
* CSPI2 with the chip select at 0. The LCD controller resides on
|
||||
* CSPI3 cs1, but we have no idea how to communicate to it */
|
||||
static struct spi_node mc13783_spi =
|
||||
{
|
||||
CSPI2_NUM, /* CSPI module 2 */
|
||||
CSPI_CONREG_CHIP_SELECT_SS0 | /* Chip select 0 */
|
||||
CSPI_CONREG_DRCTL_DONT_CARE | /* Don't care about CSPI_RDY */
|
||||
CSPI_CONREG_DATA_RATE_DIV_4 | /* Clock = IPG_CLK/4 - 16.5MHz */
|
||||
CSPI_BITCOUNT(32-1) | /* All 32 bits are to be transferred */
|
||||
CSPI_CONREG_SSPOL | /* SS active high */
|
||||
CSPI_CONREG_SSCTL | /* Negate SS between SPI bursts */
|
||||
CSPI_CONREG_MODE, /* Master mode */
|
||||
0, /* SPI clock - no wait states */
|
||||
};
|
||||
|
||||
static int mc13783_thread_stack[DEFAULT_STACK_SIZE/sizeof(int)];
|
||||
static const char *mc13783_thread_name = "pmic";
|
||||
static struct wakeup mc13783_wake;
|
||||
|
||||
static __attribute__((noreturn)) void mc13783_interrupt_thread(void)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
wakeup_wait(&mc13783_wake, TIMEOUT_BLOCK);
|
||||
}
|
||||
}
|
||||
|
||||
static __attribute__((interrupt("IRQ"))) void mc13783_interrupt(void)
|
||||
{
|
||||
wakeup_signal(&mc13783_wake);
|
||||
}
|
||||
|
||||
void mc13783_init(void)
|
||||
{
|
||||
/* Serial interface must have been initialized first! */
|
||||
wakeup_init(&mc13783_wake);
|
||||
|
||||
/* Enable the PMIC SPI module */
|
||||
spi_enable_module(&mc13783_spi);
|
||||
|
||||
create_thread(mc13783_interrupt_thread, mc13783_thread_stack,
|
||||
sizeof(mc13783_thread_stack), 0, mc13783_thread_name
|
||||
IF_PRIO(, PRIORITY_REALTIME) IF_COP(, CPU));
|
||||
}
|
||||
|
||||
void mc13783_set(unsigned address, uint32_t bits)
|
||||
{
|
||||
spi_lock(&mc13783_spi);
|
||||
uint32_t data = mc13783_read(address);
|
||||
mc13783_write(address, data | bits);
|
||||
spi_unlock(&mc13783_spi);
|
||||
}
|
||||
|
||||
void mc13783_clear(unsigned address, uint32_t bits)
|
||||
{
|
||||
spi_lock(&mc13783_spi);
|
||||
uint32_t data = mc13783_read(address);
|
||||
mc13783_write(address, data & ~bits);
|
||||
spi_unlock(&mc13783_spi);
|
||||
}
|
||||
|
||||
int mc13783_write(unsigned address, uint32_t data)
|
||||
{
|
||||
struct spi_transfer xfer;
|
||||
uint32_t packet;
|
||||
|
||||
if (address >= MC13783_NUM_REGS)
|
||||
return -1;
|
||||
|
||||
packet = (1 << 31) | (address << 25) | (data & 0xffffff);
|
||||
xfer.txbuf = &packet;
|
||||
xfer.rxbuf = &packet;
|
||||
xfer.count = 1;
|
||||
|
||||
if (!spi_transfer(&mc13783_spi, &xfer))
|
||||
return -1;
|
||||
|
||||
return 1 - xfer.count;
|
||||
}
|
||||
|
||||
int mc13783_write_multiple(unsigned start, const uint32_t *data, int count)
|
||||
{
|
||||
int i;
|
||||
struct spi_transfer xfer;
|
||||
uint32_t packets[64];
|
||||
|
||||
if (start + count > MC13783_NUM_REGS)
|
||||
return -1;
|
||||
|
||||
/* Prepare payload */
|
||||
for (i = 0; i < count; i++, start++)
|
||||
{
|
||||
packets[i] = (1 << 31) | (start << 25) | (data[i] & 0xffffff);
|
||||
}
|
||||
|
||||
xfer.txbuf = packets;
|
||||
xfer.rxbuf = packets;
|
||||
xfer.count = count;
|
||||
|
||||
if (!spi_transfer(&mc13783_spi, &xfer))
|
||||
return -1;
|
||||
|
||||
return count - xfer.count;
|
||||
}
|
||||
|
||||
uint32_t mc13783_read(unsigned address)
|
||||
{
|
||||
uint32_t packet;
|
||||
struct spi_transfer xfer;
|
||||
|
||||
if (address >= MC13783_NUM_REGS)
|
||||
return (uint32_t)-1;
|
||||
|
||||
packet = address << 25;
|
||||
|
||||
xfer.txbuf = &packet;
|
||||
xfer.rxbuf = &packet;
|
||||
xfer.count = 1;
|
||||
|
||||
if (!spi_transfer(&mc13783_spi, &xfer))
|
||||
return (uint32_t)-1;
|
||||
|
||||
return packet & 0xffffff;
|
||||
}
|
||||
|
||||
int mc13783_read_multiple(unsigned start, uint32_t *buffer, int count)
|
||||
{
|
||||
int i;
|
||||
uint32_t packets[64];
|
||||
struct spi_transfer xfer;
|
||||
|
||||
if (start + count > MC13783_NUM_REGS)
|
||||
return -1;
|
||||
|
||||
xfer.txbuf = packets;
|
||||
xfer.rxbuf = buffer;
|
||||
xfer.count = count;
|
||||
|
||||
/* Prepare TX payload */
|
||||
for (i = 0; i < count; i++, start++)
|
||||
packets[i] = start << 25;
|
||||
|
||||
if (!spi_transfer(&mc13783_spi, &xfer))
|
||||
return -1;
|
||||
|
||||
return count - xfer.count;
|
||||
}
|
||||
|
|
@ -18,66 +18,325 @@
|
|||
****************************************************************************/
|
||||
#include "cpu.h"
|
||||
#include "spi-imx31.h"
|
||||
#include "avic-imx31.h"
|
||||
#include "clkctl-imx31.h"
|
||||
#include "debug.h"
|
||||
#include "kernel.h"
|
||||
|
||||
/* This is all based on communicating with the MC13783 PMU which is on
|
||||
* CSPI2 with the chip select at 0. The LCD controller resides on
|
||||
* CSPI3 cs1, but we have no idea how to communicate to it */
|
||||
/* Forward interrupt handler declarations */
|
||||
#if (SPI_MODULE_MASK & USE_CSPI1_MODULE)
|
||||
static __attribute__((interrupt("IRQ"))) void CSPI1_HANDLER(void);
|
||||
#endif
|
||||
#if (SPI_MODULE_MASK & USE_CSPI2_MODULE)
|
||||
static __attribute__((interrupt("IRQ"))) void CSPI2_HANDLER(void);
|
||||
#endif
|
||||
#if (SPI_MODULE_MASK & USE_CSPI3_MODULE)
|
||||
static __attribute__((interrupt("IRQ"))) void CSPI3_HANDLER(void);
|
||||
#endif
|
||||
|
||||
void spi_init(void) {
|
||||
CSPI_CONREG2 |= (2 << 20); // Burst will be triggered at SPI_RDY low
|
||||
CSPI_CONREG2 |= (2 << 16); // Clock = IPG_CLK/16 - we want about 20mhz
|
||||
CSPI_CONREG2 |= (31 << 8); // All 32 bits are to be transferred
|
||||
CSPI_CONREG2 |= (1 << 3); // Start burst on TXFIFO write.
|
||||
CSPI_CONREG2 |= (1 << 1); // Master mode.
|
||||
CSPI_CONREG2 |= 1; // Enable CSPI2;
|
||||
}
|
||||
/* State data associatated with each CSPI module */
|
||||
static struct spi_module_descriptor
|
||||
{
|
||||
volatile unsigned long *base;
|
||||
int enab;
|
||||
struct spi_node *last;
|
||||
enum IMX31_CG_LIST cg;
|
||||
enum IMX31_INT_LIST ints;
|
||||
int byte_size;
|
||||
void (*handler)(void);
|
||||
struct mutex m;
|
||||
struct wakeup w;
|
||||
struct spi_transfer *trans;
|
||||
int rxcount;
|
||||
} spi_descs[SPI_NUM_CSPI] =
|
||||
/* Init non-zero members */
|
||||
{
|
||||
#if (SPI_MODULE_MASK & USE_CSPI1_MODULE)
|
||||
{
|
||||
.base = (unsigned long *)CSPI1_BASE_ADDR,
|
||||
.cg = CG_CSPI1,
|
||||
.ints = CSPI1,
|
||||
.handler = CSPI1_HANDLER,
|
||||
},
|
||||
#endif
|
||||
#if (SPI_MODULE_MASK & USE_CSPI2_MODULE)
|
||||
{
|
||||
.base = (unsigned long *)CSPI2_BASE_ADDR,
|
||||
.cg = CG_CSPI2,
|
||||
.ints = CSPI2,
|
||||
.handler = CSPI2_HANDLER,
|
||||
},
|
||||
#endif
|
||||
#if (SPI_MODULE_MASK & USE_CSPI3_MODULE)
|
||||
{
|
||||
.base = (unsigned long *)CSPI3_BASE_ADDR,
|
||||
.cg = CG_CSPI3,
|
||||
.ints = CSPI3,
|
||||
.handler = CSPI3_HANDLER,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
static int spi_transfer(int address, long data, long* buffer, bool read) {
|
||||
return -1; /* Disable for now - hangs - and we'll use interrupts */
|
||||
/* Common code for interrupt handlers */
|
||||
static void spi_interrupt(enum spi_module_number spi)
|
||||
{
|
||||
struct spi_module_descriptor *desc = &spi_descs[spi];
|
||||
volatile unsigned long * const base = desc->base;
|
||||
struct spi_transfer *trans = desc->trans;
|
||||
int inc = desc->byte_size + 1;
|
||||
|
||||
unsigned long packet = 0;
|
||||
if(!read) {
|
||||
/* Set the appropriate bit in the packet to indicate a write */
|
||||
packet |= (1<<31);
|
||||
if (desc->rxcount > 0)
|
||||
{
|
||||
/* Data received - empty out RXFIFO */
|
||||
while ((base[CSPI_STATREG_I] & CSPI_STATREG_RR) != 0)
|
||||
{
|
||||
uint32_t word = base[CSPI_RXDATA_I];
|
||||
|
||||
switch (desc->byte_size & 3)
|
||||
{
|
||||
case 3:
|
||||
*(unsigned char *)(trans->rxbuf + 3) = word >> 24;
|
||||
case 2:
|
||||
*(unsigned char *)(trans->rxbuf + 2) = word >> 16;
|
||||
case 1:
|
||||
*(unsigned char *)(trans->rxbuf + 1) = word >> 8;
|
||||
case 0:
|
||||
*(unsigned char *)(trans->rxbuf + 0) = word;
|
||||
}
|
||||
/* Set the address of the packet */
|
||||
packet |= (address << 25);
|
||||
|
||||
/* Ensure data only occupies 24 bits, then mash the data into the packet */
|
||||
data &= ~(DATAMASK);
|
||||
packet |= data;
|
||||
trans->rxbuf += inc;
|
||||
|
||||
/* Wait for some room in TXFIFO */
|
||||
while(CSPI_STATREG2 & (1<<2));
|
||||
if (--desc->rxcount < 4)
|
||||
{
|
||||
unsigned long intreg = base[CSPI_INTREG_I];
|
||||
|
||||
/* Send the packet */
|
||||
CSPI_TXDATA2 = packet;
|
||||
if (desc->rxcount <= 0)
|
||||
{
|
||||
/* No more to receive - stop RX interrupts */
|
||||
intreg &= ~(CSPI_INTREG_RHEN | CSPI_INTREG_RREN);
|
||||
base[CSPI_INTREG_I] = intreg;
|
||||
break;
|
||||
}
|
||||
else if (!(intreg & CSPI_INTREG_RREN))
|
||||
{
|
||||
/* < 4 words expected - switch to RX ready */
|
||||
intreg &= ~CSPI_INTREG_RHEN;
|
||||
base[CSPI_INTREG_I] = intreg | CSPI_INTREG_RREN;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Poll the XCH bit to wait for the end of the transfer, with
|
||||
* a one second timeout */
|
||||
int newtick = current_tick + HZ;
|
||||
while((CSPI_CONREG2 & (1<<2)) && (current_tick < newtick));
|
||||
if (trans->count > 0)
|
||||
{
|
||||
/* Data to transmit - fill TXFIFO or write until exhausted */
|
||||
while ((base[CSPI_STATREG_I] & CSPI_STATREG_TF) == 0)
|
||||
{
|
||||
uint32_t word = 0;
|
||||
|
||||
if(newtick > current_tick) {
|
||||
*buffer = CSPI_RXDATA2;
|
||||
return 0;
|
||||
} else {
|
||||
/* Indicate the fact that the transfer timed out */
|
||||
return -1;
|
||||
switch (desc->byte_size & 3)
|
||||
{
|
||||
case 3:
|
||||
word = *(unsigned char *)(trans->txbuf + 3) << 24;
|
||||
case 2:
|
||||
word |= *(unsigned char *)(trans->txbuf + 2) << 16;
|
||||
case 1:
|
||||
word |= *(unsigned char *)(trans->txbuf + 1) << 8;
|
||||
case 0:
|
||||
word |= *(unsigned char *)(trans->txbuf + 0);
|
||||
}
|
||||
|
||||
trans->txbuf += inc;
|
||||
|
||||
base[CSPI_TXDATA_I] = word;
|
||||
|
||||
if (--trans->count <= 0)
|
||||
{
|
||||
/* Out of data - stop TX interrupts */
|
||||
base[CSPI_INTREG_I] &= ~CSPI_INTREG_THEN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If all interrupts have been remasked - we're done */
|
||||
if (base[CSPI_INTREG_I] == 0)
|
||||
{
|
||||
base[CSPI_STATREG_I] = CSPI_STATREG_TC | CSPI_STATREG_BO;
|
||||
wakeup_signal(&desc->w);
|
||||
}
|
||||
}
|
||||
|
||||
void spi_send(int address, unsigned long data) {
|
||||
long dummy;
|
||||
if(spi_transfer(address, data, &dummy, false)) {
|
||||
DEBUGF("SPI Send timed out");
|
||||
/* Interrupt handlers for each CSPI module */
|
||||
#if (SPI_MODULE_MASK & USE_CSPI1_MODULE)
|
||||
static __attribute__((interrupt("IRQ"))) void CSPI1_HANDLER(void)
|
||||
{
|
||||
spi_interrupt(CSPI1_NUM);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (SPI_MODULE_MASK & USE_CSPI2_MODULE)
|
||||
static __attribute__((interrupt("IRQ"))) void CSPI2_HANDLER(void)
|
||||
{
|
||||
spi_interrupt(CSPI2_NUM);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (SPI_MODULE_MASK & USE_CSPI3_MODULE)
|
||||
static __attribute__((interrupt("IRQ"))) void CSPI3_HANDLER(void)
|
||||
{
|
||||
spi_interrupt(CSPI3_NUM);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Write the context for the node and remember it to avoid unneeded reconfigure */
|
||||
static bool spi_set_context(struct spi_node *node,
|
||||
struct spi_module_descriptor *desc)
|
||||
{
|
||||
volatile unsigned long * const base = desc->base;
|
||||
|
||||
if ((base[CSPI_CONREG_I] & CSPI_CONREG_EN) == 0)
|
||||
return false;
|
||||
|
||||
if (node != desc->last)
|
||||
{
|
||||
/* Switch the module's node */
|
||||
desc->last = node;
|
||||
desc->byte_size = (((node->conreg >> 8) & 0x1f) + 1 + 7) / 8 - 1;
|
||||
|
||||
/* Keep reserved and start bits cleared. Keep enabled bit. */
|
||||
base[CSPI_CONREG_I] =
|
||||
(node->conreg & ~(0xfcc8e000 | CSPI_CONREG_XCH | CSPI_CONREG_SMC))
|
||||
| CSPI_CONREG_EN;
|
||||
/* Set the wait-states */
|
||||
base[CSPI_PERIODREG_I] = node->periodreg & 0xffff;
|
||||
/* Clear out any spuriously-pending interrupts */
|
||||
base[CSPI_STATREG_I] = CSPI_STATREG_TC | CSPI_STATREG_BO;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Initialize each of the used SPI descriptors */
|
||||
void spi_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SPI_NUM_CSPI; i++)
|
||||
{
|
||||
struct spi_module_descriptor * const desc = &spi_descs[i];
|
||||
mutex_init(&desc->m);
|
||||
wakeup_init(&desc->w);
|
||||
}
|
||||
}
|
||||
|
||||
void spi_read(int address, unsigned long* buffer) {
|
||||
if(spi_transfer(address, 0, buffer, true)) {
|
||||
DEBUGF("SPI read timed out");
|
||||
}
|
||||
/* Get mutually-exclusive access to the node */
|
||||
void spi_lock(struct spi_node *node)
|
||||
{
|
||||
mutex_lock(&spi_descs[node->num].m);
|
||||
}
|
||||
|
||||
/* Release mutual exclusion */
|
||||
void spi_unlock(struct spi_node *node)
|
||||
{
|
||||
mutex_unlock(&spi_descs[node->num].m);
|
||||
}
|
||||
|
||||
/* Enable the specified module for the node */
|
||||
void spi_enable_module(struct spi_node *node)
|
||||
{
|
||||
struct spi_module_descriptor * const desc = &spi_descs[node->num];
|
||||
|
||||
mutex_lock(&desc->m);
|
||||
|
||||
if (++desc->enab == 1)
|
||||
{
|
||||
/* First enable for this module */
|
||||
volatile unsigned long * const base = desc->base;
|
||||
|
||||
/* Enable clock-gating register */
|
||||
imx31_clkctl_module_clock_gating(desc->cg, CGM_ON_ALL);
|
||||
|
||||
/* Reset */
|
||||
base[CSPI_CONREG_I] &= ~CSPI_CONREG_EN;
|
||||
base[CSPI_CONREG_I] |= CSPI_CONREG_EN;
|
||||
base[CSPI_INTREG_I] = 0;
|
||||
base[CSPI_STATREG_I] = CSPI_STATREG_TC | CSPI_STATREG_BO;
|
||||
|
||||
/* Enable interrupt at controller level */
|
||||
avic_enable_int(desc->ints, IRQ, 6, desc->handler);
|
||||
}
|
||||
|
||||
mutex_unlock(&desc->m);
|
||||
}
|
||||
|
||||
/* Disabled the specified module for the node */
|
||||
void spi_disable_module(struct spi_node *node)
|
||||
{
|
||||
struct spi_module_descriptor * const desc = &spi_descs[node->num];
|
||||
|
||||
mutex_lock(&desc->m);
|
||||
|
||||
if (desc->enab > 0 && --desc->enab == 0)
|
||||
{
|
||||
/* Last enable for this module */
|
||||
volatile unsigned long * const base = desc->base;
|
||||
|
||||
/* Disable interrupt at controller level */
|
||||
avic_disable_int(desc->ints);
|
||||
|
||||
/* Disable interface */
|
||||
base[CSPI_CONREG_I] &= ~CSPI_CONREG_EN;
|
||||
|
||||
/* Disable interface clock */
|
||||
imx31_clkctl_module_clock_gating(desc->cg, CGM_OFF);
|
||||
}
|
||||
|
||||
mutex_unlock(&desc->m);
|
||||
}
|
||||
|
||||
/* Send and/or receive data on the specified node */
|
||||
int spi_transfer(struct spi_node *node, struct spi_transfer *trans)
|
||||
{
|
||||
struct spi_module_descriptor * const desc = &spi_descs[node->num];
|
||||
int retval;
|
||||
|
||||
if (trans->count <= 0)
|
||||
return true;
|
||||
|
||||
mutex_lock(&desc->m);
|
||||
|
||||
retval = spi_set_context(node, desc);
|
||||
|
||||
if (retval)
|
||||
{
|
||||
volatile unsigned long * const base = desc->base;
|
||||
unsigned long intreg;
|
||||
|
||||
desc->trans = trans;
|
||||
desc->rxcount = trans->count;
|
||||
|
||||
/* Enable needed interrupts - FIFOs will start filling */
|
||||
intreg = CSPI_INTREG_THEN;
|
||||
|
||||
intreg |= (trans->count < 4) ?
|
||||
CSPI_INTREG_RREN : /* Must grab data on every word */
|
||||
CSPI_INTREG_RHEN; /* Enough data to wait for half-full */
|
||||
|
||||
base[CSPI_INTREG_I] = intreg;
|
||||
|
||||
/* Start transfer */
|
||||
base[CSPI_CONREG_I] |= CSPI_CONREG_XCH;
|
||||
|
||||
if (wakeup_wait(&desc->w, HZ) != OBJ_WAIT_SUCCEEDED)
|
||||
{
|
||||
base[CSPI_INTREG_I] = 0;
|
||||
base[CSPI_CONREG_I] &= ~CSPI_CONREG_XCH;
|
||||
retval = false;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&desc->m);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,8 +16,58 @@
|
|||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#define DATAMASK 0xFF000000
|
||||
#ifndef _SPI_IMX31_H_
|
||||
#define _SPI_IMX31_H_
|
||||
|
||||
#define USE_CSPI1_MODULE (1 << 0)
|
||||
#define USE_CSPI2_MODULE (1 << 1)
|
||||
#define USE_CSPI3_MODULE (1 << 2)
|
||||
|
||||
/* SPI_MODULE_MASK is set in target's config */
|
||||
enum spi_module_number
|
||||
{
|
||||
#if (SPI_MODULE_MASK & USE_CSPI1_MODULE)
|
||||
CSPI1_NUM = 0,
|
||||
#endif
|
||||
#if (SPI_MODULE_MASK & USE_CSPI2_MODULE)
|
||||
CSPI2_NUM,
|
||||
#endif
|
||||
#if (SPI_MODULE_MASK & USE_CSPI3_MODULE)
|
||||
CSPI3_NUM,
|
||||
#endif
|
||||
SPI_NUM_CSPI,
|
||||
};
|
||||
|
||||
struct spi_node
|
||||
{
|
||||
enum spi_module_number num; /* Module number (CSPIx_NUM) */
|
||||
unsigned long conreg; /* CSPI conreg setup */
|
||||
unsigned long periodreg; /* CSPI periodreg setup */
|
||||
};
|
||||
|
||||
struct spi_transfer
|
||||
{
|
||||
const void *txbuf;
|
||||
void *rxbuf;
|
||||
int count;
|
||||
};
|
||||
|
||||
/* One-time init of SPI driver */
|
||||
void spi_init(void);
|
||||
void spi_send(int address, unsigned long data);
|
||||
void spi_read(int address, unsigned long* buffer);
|
||||
|
||||
/* Enable the specified module for the node */
|
||||
void spi_enable_module(struct spi_node *node);
|
||||
|
||||
/* Disabled the specified module for the node */
|
||||
void spi_disable_module(struct spi_node *node);
|
||||
|
||||
/* Lock module mutex */
|
||||
void spi_lock(struct spi_node *node);
|
||||
|
||||
/* Unlock module mutex */
|
||||
void spi_unlock(struct spi_node *node);
|
||||
|
||||
/* Send and/or receive data on the specified node */
|
||||
int spi_transfer(struct spi_node *node, struct spi_transfer *trans);
|
||||
|
||||
#endif /* _SPI_IMX31_H_ */
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@ static inline void udelay(unsigned int usecs)
|
|||
|
||||
void system_prepare_fw_start(void);
|
||||
void tick_stop(void);
|
||||
void kernel_device_init(void);
|
||||
|
||||
#define KDEV_INIT
|
||||
|
||||
#define HAVE_INVALIDATE_ICACHE
|
||||
static inline void invalidate_icache(void)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue