mirror of
https://github.com/torvalds/linux.git
synced 2024-11-28 23:21:31 +00:00
[PATCH] ARM: 2807/1: OMAP update 7a/11: Move arch-omap to plat-omap
Patch from Tony Lindgren This patch move common OMAP code from arch-omap to plat-omap directory. Signed-off-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
parent
f577ffd75c
commit
60906a8a4e
@ -1,99 +0,0 @@
|
||||
if ARCH_OMAP
|
||||
|
||||
menu "TI OMAP Implementations"
|
||||
|
||||
config ARCH_OMAP_OTG
|
||||
bool
|
||||
|
||||
choice
|
||||
prompt "OMAP System Type"
|
||||
default ARCH_OMAP1
|
||||
|
||||
config ARCH_OMAP1
|
||||
bool "TI OMAP1"
|
||||
|
||||
config ARCH_OMAP2
|
||||
bool "TI OMAP2"
|
||||
|
||||
endchoice
|
||||
|
||||
comment "OMAP Feature Selections"
|
||||
|
||||
config OMAP_MUX
|
||||
bool "OMAP multiplexing support"
|
||||
depends on ARCH_OMAP
|
||||
default y
|
||||
help
|
||||
Pin multiplexing support for OMAP boards. If your bootloader
|
||||
sets the multiplexing correctly, say N. Otherwise, or if unsure,
|
||||
say Y.
|
||||
|
||||
config OMAP_MUX_DEBUG
|
||||
bool "Multiplexing debug output"
|
||||
depends on OMAP_MUX
|
||||
default n
|
||||
help
|
||||
Makes the multiplexing functions print out a lot of debug info.
|
||||
This is useful if you want to find out the correct values of the
|
||||
multiplexing registers.
|
||||
|
||||
config OMAP_MUX_WARNINGS
|
||||
bool "Warn about pins the bootloader didn't set up"
|
||||
depends on OMAP_MUX
|
||||
default y
|
||||
help
|
||||
Choose Y here to warn whenever driver initialization logic needs
|
||||
to change the pin multiplexing setup. When there are no warnings
|
||||
printed, it's safe to deselect OMAP_MUX for your product.
|
||||
|
||||
choice
|
||||
prompt "System timer"
|
||||
default OMAP_MPU_TIMER
|
||||
|
||||
config OMAP_MPU_TIMER
|
||||
bool "Use mpu timer"
|
||||
help
|
||||
Select this option if you want to use the OMAP mpu timer. This
|
||||
timer provides more intra-tick resolution than the 32KHz timer,
|
||||
but consumes more power.
|
||||
|
||||
config OMAP_32K_TIMER
|
||||
bool "Use 32KHz timer"
|
||||
depends on ARCH_OMAP16XX
|
||||
help
|
||||
Select this option if you want to enable the OMAP 32KHz timer.
|
||||
This timer saves power compared to the OMAP_MPU_TIMER, and has
|
||||
support for no tick during idle. The 32KHz timer provides less
|
||||
intra-tick resolution than OMAP_MPU_TIMER. The 32KHz timer is
|
||||
currently only available for OMAP-16xx.
|
||||
|
||||
endchoice
|
||||
|
||||
config OMAP_32K_TIMER_HZ
|
||||
int "Kernel internal timer frequency for 32KHz timer"
|
||||
range 32 1024
|
||||
depends on OMAP_32K_TIMER
|
||||
default "128"
|
||||
help
|
||||
Kernel internal timer frequency should be a divisor of 32768,
|
||||
such as 64 or 128.
|
||||
|
||||
choice
|
||||
prompt "Low-level debug console UART"
|
||||
depends on ARCH_OMAP
|
||||
default OMAP_LL_DEBUG_UART1
|
||||
|
||||
config OMAP_LL_DEBUG_UART1
|
||||
bool "UART1"
|
||||
|
||||
config OMAP_LL_DEBUG_UART2
|
||||
bool "UART2"
|
||||
|
||||
config OMAP_LL_DEBUG_UART3
|
||||
bool "UART3"
|
||||
|
||||
endchoice
|
||||
|
||||
endmenu
|
||||
|
||||
endif
|
@ -1,16 +0,0 @@
|
||||
#
|
||||
# Makefile for the linux kernel.
|
||||
#
|
||||
|
||||
# Common support
|
||||
obj-y := common.o dma.o clock.o mux.o gpio.o mcbsp.o usb.o
|
||||
obj-m :=
|
||||
obj-n :=
|
||||
obj- :=
|
||||
|
||||
# OCPI interconnect support for 1710, 1610 and 5912
|
||||
obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
|
||||
|
||||
# Power Management
|
||||
obj-$(CONFIG_PM) += pm.o sleep.o
|
||||
|
@ -1,135 +0,0 @@
|
||||
/*
|
||||
* linux/arch/arm/mach-omap/common.c
|
||||
*
|
||||
* Code common to all OMAP machines.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/serial_reg.h>
|
||||
|
||||
#include <asm/hardware.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/mach/map.h>
|
||||
#include <asm/hardware/clock.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
#include <asm/arch/board.h>
|
||||
#include <asm/arch/mux.h>
|
||||
#include <asm/arch/fpga.h>
|
||||
|
||||
#include "clock.h"
|
||||
|
||||
#define NO_LENGTH_CHECK 0xffffffff
|
||||
|
||||
extern int omap_bootloader_tag_len;
|
||||
extern u8 omap_bootloader_tag[];
|
||||
|
||||
struct omap_board_config_kernel *omap_board_config;
|
||||
int omap_board_config_size = 0;
|
||||
|
||||
static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out)
|
||||
{
|
||||
struct omap_board_config_kernel *kinfo = NULL;
|
||||
int i;
|
||||
|
||||
#ifdef CONFIG_OMAP_BOOT_TAG
|
||||
struct omap_board_config_entry *info = NULL;
|
||||
|
||||
if (omap_bootloader_tag_len > 4)
|
||||
info = (struct omap_board_config_entry *) omap_bootloader_tag;
|
||||
while (info != NULL) {
|
||||
u8 *next;
|
||||
|
||||
if (info->tag == tag) {
|
||||
if (skip == 0)
|
||||
break;
|
||||
skip--;
|
||||
}
|
||||
|
||||
if ((info->len & 0x03) != 0) {
|
||||
/* We bail out to avoid an alignment fault */
|
||||
printk(KERN_ERR "OMAP peripheral config: Length (%d) not word-aligned (tag %04x)\n",
|
||||
info->len, info->tag);
|
||||
return NULL;
|
||||
}
|
||||
next = (u8 *) info + sizeof(*info) + info->len;
|
||||
if (next >= omap_bootloader_tag + omap_bootloader_tag_len)
|
||||
info = NULL;
|
||||
else
|
||||
info = (struct omap_board_config_entry *) next;
|
||||
}
|
||||
if (info != NULL) {
|
||||
/* Check the length as a lame attempt to check for
|
||||
* binary inconsistancy. */
|
||||
if (len != NO_LENGTH_CHECK) {
|
||||
/* Word-align len */
|
||||
if (len & 0x03)
|
||||
len = (len + 3) & ~0x03;
|
||||
if (info->len != len) {
|
||||
printk(KERN_ERR "OMAP peripheral config: Length mismatch with tag %x (want %d, got %d)\n",
|
||||
tag, len, info->len);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (len_out != NULL)
|
||||
*len_out = info->len;
|
||||
return info->data;
|
||||
}
|
||||
#endif
|
||||
/* Try to find the config from the board-specific structures
|
||||
* in the kernel. */
|
||||
for (i = 0; i < omap_board_config_size; i++) {
|
||||
if (omap_board_config[i].tag == tag) {
|
||||
kinfo = &omap_board_config[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (kinfo == NULL)
|
||||
return NULL;
|
||||
return kinfo->data;
|
||||
}
|
||||
|
||||
const void *__omap_get_config(u16 tag, size_t len, int nr)
|
||||
{
|
||||
return get_config(tag, len, nr, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL(__omap_get_config);
|
||||
|
||||
const void *omap_get_var_config(u16 tag, size_t *len)
|
||||
{
|
||||
return get_config(tag, NO_LENGTH_CHECK, 0, len);
|
||||
}
|
||||
EXPORT_SYMBOL(omap_get_var_config);
|
||||
|
||||
static int __init omap_add_serial_console(void)
|
||||
{
|
||||
const struct omap_serial_console_config *info;
|
||||
|
||||
info = omap_get_config(OMAP_TAG_SERIAL_CONSOLE,
|
||||
struct omap_serial_console_config);
|
||||
if (info != NULL && info->console_uart) {
|
||||
static char speed[11], *opt = NULL;
|
||||
|
||||
if (info->console_speed) {
|
||||
snprintf(speed, sizeof(speed), "%u", info->console_speed);
|
||||
opt = speed;
|
||||
}
|
||||
return add_preferred_console("ttyS", info->console_uart - 1, opt);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
console_initcall(omap_add_serial_console);
|
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* linux/arch/arm/mach-omap/common.h
|
||||
*
|
||||
* Header for code common to all OMAP machines.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_ARM_MACH_OMAP_COMMON_H
|
||||
#define __ARCH_ARM_MACH_OMAP_COMMON_H
|
||||
|
||||
struct sys_timer;
|
||||
|
||||
extern void omap_map_common_io(void);
|
||||
extern struct sys_timer omap_timer;
|
||||
extern void omap_serial_init(int ports[]);
|
||||
|
||||
#endif /* __ARCH_ARM_MACH_OMAP_COMMON_H */
|
File diff suppressed because it is too large
Load Diff
@ -1,762 +0,0 @@
|
||||
/*
|
||||
* linux/arch/arm/mach-omap/gpio.c
|
||||
*
|
||||
* Support functions for OMAP GPIO
|
||||
*
|
||||
* Copyright (C) 2003 Nokia Corporation
|
||||
* Written by Juha Yrjölä <juha.yrjola@nokia.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ptrace.h>
|
||||
|
||||
#include <asm/hardware.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/arch/irqs.h>
|
||||
#include <asm/arch/gpio.h>
|
||||
#include <asm/mach/irq.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
/*
|
||||
* OMAP1510 GPIO registers
|
||||
*/
|
||||
#define OMAP1510_GPIO_BASE 0xfffce000
|
||||
#define OMAP1510_GPIO_DATA_INPUT 0x00
|
||||
#define OMAP1510_GPIO_DATA_OUTPUT 0x04
|
||||
#define OMAP1510_GPIO_DIR_CONTROL 0x08
|
||||
#define OMAP1510_GPIO_INT_CONTROL 0x0c
|
||||
#define OMAP1510_GPIO_INT_MASK 0x10
|
||||
#define OMAP1510_GPIO_INT_STATUS 0x14
|
||||
#define OMAP1510_GPIO_PIN_CONTROL 0x18
|
||||
|
||||
#define OMAP1510_IH_GPIO_BASE 64
|
||||
|
||||
/*
|
||||
* OMAP1610 specific GPIO registers
|
||||
*/
|
||||
#define OMAP1610_GPIO1_BASE 0xfffbe400
|
||||
#define OMAP1610_GPIO2_BASE 0xfffbec00
|
||||
#define OMAP1610_GPIO3_BASE 0xfffbb400
|
||||
#define OMAP1610_GPIO4_BASE 0xfffbbc00
|
||||
#define OMAP1610_GPIO_REVISION 0x0000
|
||||
#define OMAP1610_GPIO_SYSCONFIG 0x0010
|
||||
#define OMAP1610_GPIO_SYSSTATUS 0x0014
|
||||
#define OMAP1610_GPIO_IRQSTATUS1 0x0018
|
||||
#define OMAP1610_GPIO_IRQENABLE1 0x001c
|
||||
#define OMAP1610_GPIO_DATAIN 0x002c
|
||||
#define OMAP1610_GPIO_DATAOUT 0x0030
|
||||
#define OMAP1610_GPIO_DIRECTION 0x0034
|
||||
#define OMAP1610_GPIO_EDGE_CTRL1 0x0038
|
||||
#define OMAP1610_GPIO_EDGE_CTRL2 0x003c
|
||||
#define OMAP1610_GPIO_CLEAR_IRQENABLE1 0x009c
|
||||
#define OMAP1610_GPIO_CLEAR_DATAOUT 0x00b0
|
||||
#define OMAP1610_GPIO_SET_IRQENABLE1 0x00dc
|
||||
#define OMAP1610_GPIO_SET_DATAOUT 0x00f0
|
||||
|
||||
/*
|
||||
* OMAP730 specific GPIO registers
|
||||
*/
|
||||
#define OMAP730_GPIO1_BASE 0xfffbc000
|
||||
#define OMAP730_GPIO2_BASE 0xfffbc800
|
||||
#define OMAP730_GPIO3_BASE 0xfffbd000
|
||||
#define OMAP730_GPIO4_BASE 0xfffbd800
|
||||
#define OMAP730_GPIO5_BASE 0xfffbe000
|
||||
#define OMAP730_GPIO6_BASE 0xfffbe800
|
||||
#define OMAP730_GPIO_DATA_INPUT 0x00
|
||||
#define OMAP730_GPIO_DATA_OUTPUT 0x04
|
||||
#define OMAP730_GPIO_DIR_CONTROL 0x08
|
||||
#define OMAP730_GPIO_INT_CONTROL 0x0c
|
||||
#define OMAP730_GPIO_INT_MASK 0x10
|
||||
#define OMAP730_GPIO_INT_STATUS 0x14
|
||||
|
||||
#define OMAP_MPUIO_MASK (~OMAP_MAX_GPIO_LINES & 0xff)
|
||||
|
||||
struct gpio_bank {
|
||||
u32 base;
|
||||
u16 irq;
|
||||
u16 virtual_irq_start;
|
||||
u8 method;
|
||||
u32 reserved_map;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
#define METHOD_MPUIO 0
|
||||
#define METHOD_GPIO_1510 1
|
||||
#define METHOD_GPIO_1610 2
|
||||
#define METHOD_GPIO_730 3
|
||||
|
||||
#if defined(CONFIG_ARCH_OMAP16XX)
|
||||
static struct gpio_bank gpio_bank_1610[5] = {
|
||||
{ OMAP_MPUIO_BASE, INT_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO},
|
||||
{ OMAP1610_GPIO1_BASE, INT_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_1610 },
|
||||
{ OMAP1610_GPIO2_BASE, INT_1610_GPIO_BANK2, IH_GPIO_BASE + 16, METHOD_GPIO_1610 },
|
||||
{ OMAP1610_GPIO3_BASE, INT_1610_GPIO_BANK3, IH_GPIO_BASE + 32, METHOD_GPIO_1610 },
|
||||
{ OMAP1610_GPIO4_BASE, INT_1610_GPIO_BANK4, IH_GPIO_BASE + 48, METHOD_GPIO_1610 },
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP1510
|
||||
static struct gpio_bank gpio_bank_1510[2] = {
|
||||
{ OMAP_MPUIO_BASE, INT_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO },
|
||||
{ OMAP1510_GPIO_BASE, INT_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_1510 }
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP730
|
||||
static struct gpio_bank gpio_bank_730[7] = {
|
||||
{ OMAP_MPUIO_BASE, INT_730_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO },
|
||||
{ OMAP730_GPIO1_BASE, INT_730_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_730 },
|
||||
{ OMAP730_GPIO2_BASE, INT_730_GPIO_BANK2, IH_GPIO_BASE + 32, METHOD_GPIO_730 },
|
||||
{ OMAP730_GPIO3_BASE, INT_730_GPIO_BANK3, IH_GPIO_BASE + 64, METHOD_GPIO_730 },
|
||||
{ OMAP730_GPIO4_BASE, INT_730_GPIO_BANK4, IH_GPIO_BASE + 96, METHOD_GPIO_730 },
|
||||
{ OMAP730_GPIO5_BASE, INT_730_GPIO_BANK5, IH_GPIO_BASE + 128, METHOD_GPIO_730 },
|
||||
{ OMAP730_GPIO6_BASE, INT_730_GPIO_BANK6, IH_GPIO_BASE + 160, METHOD_GPIO_730 },
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct gpio_bank *gpio_bank;
|
||||
static int gpio_bank_count;
|
||||
|
||||
static inline struct gpio_bank *get_gpio_bank(int gpio)
|
||||
{
|
||||
#ifdef CONFIG_ARCH_OMAP1510
|
||||
if (cpu_is_omap1510()) {
|
||||
if (OMAP_GPIO_IS_MPUIO(gpio))
|
||||
return &gpio_bank[0];
|
||||
return &gpio_bank[1];
|
||||
}
|
||||
#endif
|
||||
#if defined(CONFIG_ARCH_OMAP16XX)
|
||||
if (cpu_is_omap16xx()) {
|
||||
if (OMAP_GPIO_IS_MPUIO(gpio))
|
||||
return &gpio_bank[0];
|
||||
return &gpio_bank[1 + (gpio >> 4)];
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_OMAP730
|
||||
if (cpu_is_omap730()) {
|
||||
if (OMAP_GPIO_IS_MPUIO(gpio))
|
||||
return &gpio_bank[0];
|
||||
return &gpio_bank[1 + (gpio >> 5)];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int get_gpio_index(int gpio)
|
||||
{
|
||||
if (cpu_is_omap730())
|
||||
return gpio & 0x1f;
|
||||
else
|
||||
return gpio & 0x0f;
|
||||
}
|
||||
|
||||
static inline int gpio_valid(int gpio)
|
||||
{
|
||||
if (gpio < 0)
|
||||
return -1;
|
||||
if (OMAP_GPIO_IS_MPUIO(gpio)) {
|
||||
if ((gpio & OMAP_MPUIO_MASK) > 16)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
#ifdef CONFIG_ARCH_OMAP1510
|
||||
if (cpu_is_omap1510() && gpio < 16)
|
||||
return 0;
|
||||
#endif
|
||||
#if defined(CONFIG_ARCH_OMAP16XX)
|
||||
if ((cpu_is_omap16xx()) && gpio < 64)
|
||||
return 0;
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_OMAP730
|
||||
if (cpu_is_omap730() && gpio < 192)
|
||||
return 0;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int check_gpio(int gpio)
|
||||
{
|
||||
if (unlikely(gpio_valid(gpio)) < 0) {
|
||||
printk(KERN_ERR "omap-gpio: invalid GPIO %d\n", gpio);
|
||||
dump_stack();
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
|
||||
{
|
||||
u32 reg = bank->base;
|
||||
u32 l;
|
||||
|
||||
switch (bank->method) {
|
||||
case METHOD_MPUIO:
|
||||
reg += OMAP_MPUIO_IO_CNTL;
|
||||
break;
|
||||
case METHOD_GPIO_1510:
|
||||
reg += OMAP1510_GPIO_DIR_CONTROL;
|
||||
break;
|
||||
case METHOD_GPIO_1610:
|
||||
reg += OMAP1610_GPIO_DIRECTION;
|
||||
break;
|
||||
case METHOD_GPIO_730:
|
||||
reg += OMAP730_GPIO_DIR_CONTROL;
|
||||
break;
|
||||
}
|
||||
l = __raw_readl(reg);
|
||||
if (is_input)
|
||||
l |= 1 << gpio;
|
||||
else
|
||||
l &= ~(1 << gpio);
|
||||
__raw_writel(l, reg);
|
||||
}
|
||||
|
||||
void omap_set_gpio_direction(int gpio, int is_input)
|
||||
{
|
||||
struct gpio_bank *bank;
|
||||
|
||||
if (check_gpio(gpio) < 0)
|
||||
return;
|
||||
bank = get_gpio_bank(gpio);
|
||||
spin_lock(&bank->lock);
|
||||
_set_gpio_direction(bank, get_gpio_index(gpio), is_input);
|
||||
spin_unlock(&bank->lock);
|
||||
}
|
||||
|
||||
static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable)
|
||||
{
|
||||
u32 reg = bank->base;
|
||||
u32 l = 0;
|
||||
|
||||
switch (bank->method) {
|
||||
case METHOD_MPUIO:
|
||||
reg += OMAP_MPUIO_OUTPUT;
|
||||
l = __raw_readl(reg);
|
||||
if (enable)
|
||||
l |= 1 << gpio;
|
||||
else
|
||||
l &= ~(1 << gpio);
|
||||
break;
|
||||
case METHOD_GPIO_1510:
|
||||
reg += OMAP1510_GPIO_DATA_OUTPUT;
|
||||
l = __raw_readl(reg);
|
||||
if (enable)
|
||||
l |= 1 << gpio;
|
||||
else
|
||||
l &= ~(1 << gpio);
|
||||
break;
|
||||
case METHOD_GPIO_1610:
|
||||
if (enable)
|
||||
reg += OMAP1610_GPIO_SET_DATAOUT;
|
||||
else
|
||||
reg += OMAP1610_GPIO_CLEAR_DATAOUT;
|
||||
l = 1 << gpio;
|
||||
break;
|
||||
case METHOD_GPIO_730:
|
||||
reg += OMAP730_GPIO_DATA_OUTPUT;
|
||||
l = __raw_readl(reg);
|
||||
if (enable)
|
||||
l |= 1 << gpio;
|
||||
else
|
||||
l &= ~(1 << gpio);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
return;
|
||||
}
|
||||
__raw_writel(l, reg);
|
||||
}
|
||||
|
||||
void omap_set_gpio_dataout(int gpio, int enable)
|
||||
{
|
||||
struct gpio_bank *bank;
|
||||
|
||||
if (check_gpio(gpio) < 0)
|
||||
return;
|
||||
bank = get_gpio_bank(gpio);
|
||||
spin_lock(&bank->lock);
|
||||
_set_gpio_dataout(bank, get_gpio_index(gpio), enable);
|
||||
spin_unlock(&bank->lock);
|
||||
}
|
||||
|
||||
int omap_get_gpio_datain(int gpio)
|
||||
{
|
||||
struct gpio_bank *bank;
|
||||
u32 reg;
|
||||
|
||||
if (check_gpio(gpio) < 0)
|
||||
return -1;
|
||||
bank = get_gpio_bank(gpio);
|
||||
reg = bank->base;
|
||||
switch (bank->method) {
|
||||
case METHOD_MPUIO:
|
||||
reg += OMAP_MPUIO_INPUT_LATCH;
|
||||
break;
|
||||
case METHOD_GPIO_1510:
|
||||
reg += OMAP1510_GPIO_DATA_INPUT;
|
||||
break;
|
||||
case METHOD_GPIO_1610:
|
||||
reg += OMAP1610_GPIO_DATAIN;
|
||||
break;
|
||||
case METHOD_GPIO_730:
|
||||
reg += OMAP730_GPIO_DATA_INPUT;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
return -1;
|
||||
}
|
||||
return (__raw_readl(reg) & (1 << get_gpio_index(gpio))) != 0;
|
||||
}
|
||||
|
||||
static void _set_gpio_edge_ctrl(struct gpio_bank *bank, int gpio, int edge)
|
||||
{
|
||||
u32 reg = bank->base;
|
||||
u32 l;
|
||||
|
||||
switch (bank->method) {
|
||||
case METHOD_MPUIO:
|
||||
reg += OMAP_MPUIO_GPIO_INT_EDGE;
|
||||
l = __raw_readl(reg);
|
||||
if (edge == OMAP_GPIO_RISING_EDGE)
|
||||
l |= 1 << gpio;
|
||||
else
|
||||
l &= ~(1 << gpio);
|
||||
__raw_writel(l, reg);
|
||||
break;
|
||||
case METHOD_GPIO_1510:
|
||||
reg += OMAP1510_GPIO_INT_CONTROL;
|
||||
l = __raw_readl(reg);
|
||||
if (edge == OMAP_GPIO_RISING_EDGE)
|
||||
l |= 1 << gpio;
|
||||
else
|
||||
l &= ~(1 << gpio);
|
||||
__raw_writel(l, reg);
|
||||
break;
|
||||
case METHOD_GPIO_1610:
|
||||
edge &= 0x03;
|
||||
if (gpio & 0x08)
|
||||
reg += OMAP1610_GPIO_EDGE_CTRL2;
|
||||
else
|
||||
reg += OMAP1610_GPIO_EDGE_CTRL1;
|
||||
gpio &= 0x07;
|
||||
l = __raw_readl(reg);
|
||||
l &= ~(3 << (gpio << 1));
|
||||
l |= edge << (gpio << 1);
|
||||
__raw_writel(l, reg);
|
||||
break;
|
||||
case METHOD_GPIO_730:
|
||||
reg += OMAP730_GPIO_INT_CONTROL;
|
||||
l = __raw_readl(reg);
|
||||
if (edge == OMAP_GPIO_RISING_EDGE)
|
||||
l |= 1 << gpio;
|
||||
else
|
||||
l &= ~(1 << gpio);
|
||||
__raw_writel(l, reg);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void omap_set_gpio_edge_ctrl(int gpio, int edge)
|
||||
{
|
||||
struct gpio_bank *bank;
|
||||
|
||||
if (check_gpio(gpio) < 0)
|
||||
return;
|
||||
bank = get_gpio_bank(gpio);
|
||||
spin_lock(&bank->lock);
|
||||
_set_gpio_edge_ctrl(bank, get_gpio_index(gpio), edge);
|
||||
spin_unlock(&bank->lock);
|
||||
}
|
||||
|
||||
|
||||
static int _get_gpio_edge_ctrl(struct gpio_bank *bank, int gpio)
|
||||
{
|
||||
u32 reg = bank->base, l;
|
||||
|
||||
switch (bank->method) {
|
||||
case METHOD_MPUIO:
|
||||
l = __raw_readl(reg + OMAP_MPUIO_GPIO_INT_EDGE);
|
||||
return (l & (1 << gpio)) ?
|
||||
OMAP_GPIO_RISING_EDGE : OMAP_GPIO_FALLING_EDGE;
|
||||
case METHOD_GPIO_1510:
|
||||
l = __raw_readl(reg + OMAP1510_GPIO_INT_CONTROL);
|
||||
return (l & (1 << gpio)) ?
|
||||
OMAP_GPIO_RISING_EDGE : OMAP_GPIO_FALLING_EDGE;
|
||||
case METHOD_GPIO_1610:
|
||||
if (gpio & 0x08)
|
||||
reg += OMAP1610_GPIO_EDGE_CTRL2;
|
||||
else
|
||||
reg += OMAP1610_GPIO_EDGE_CTRL1;
|
||||
return (__raw_readl(reg) >> ((gpio & 0x07) << 1)) & 0x03;
|
||||
case METHOD_GPIO_730:
|
||||
l = __raw_readl(reg + OMAP730_GPIO_INT_CONTROL);
|
||||
return (l & (1 << gpio)) ?
|
||||
OMAP_GPIO_RISING_EDGE : OMAP_GPIO_FALLING_EDGE;
|
||||
default:
|
||||
BUG();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
|
||||
{
|
||||
u32 reg = bank->base;
|
||||
|
||||
switch (bank->method) {
|
||||
case METHOD_MPUIO:
|
||||
/* MPUIO irqstatus is reset by reading the status register,
|
||||
* so do nothing here */
|
||||
return;
|
||||
case METHOD_GPIO_1510:
|
||||
reg += OMAP1510_GPIO_INT_STATUS;
|
||||
break;
|
||||
case METHOD_GPIO_1610:
|
||||
reg += OMAP1610_GPIO_IRQSTATUS1;
|
||||
break;
|
||||
case METHOD_GPIO_730:
|
||||
reg += OMAP730_GPIO_INT_STATUS;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
return;
|
||||
}
|
||||
__raw_writel(gpio_mask, reg);
|
||||
}
|
||||
|
||||
static inline void _clear_gpio_irqstatus(struct gpio_bank *bank, int gpio)
|
||||
{
|
||||
_clear_gpio_irqbank(bank, 1 << get_gpio_index(gpio));
|
||||
}
|
||||
|
||||
static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enable)
|
||||
{
|
||||
u32 reg = bank->base;
|
||||
u32 l;
|
||||
|
||||
switch (bank->method) {
|
||||
case METHOD_MPUIO:
|
||||
reg += OMAP_MPUIO_GPIO_MASKIT;
|
||||
l = __raw_readl(reg);
|
||||
if (enable)
|
||||
l &= ~(gpio_mask);
|
||||
else
|
||||
l |= gpio_mask;
|
||||
break;
|
||||
case METHOD_GPIO_1510:
|
||||
reg += OMAP1510_GPIO_INT_MASK;
|
||||
l = __raw_readl(reg);
|
||||
if (enable)
|
||||
l &= ~(gpio_mask);
|
||||
else
|
||||
l |= gpio_mask;
|
||||
break;
|
||||
case METHOD_GPIO_1610:
|
||||
if (enable)
|
||||
reg += OMAP1610_GPIO_SET_IRQENABLE1;
|
||||
else
|
||||
reg += OMAP1610_GPIO_CLEAR_IRQENABLE1;
|
||||
l = gpio_mask;
|
||||
break;
|
||||
case METHOD_GPIO_730:
|
||||
reg += OMAP730_GPIO_INT_MASK;
|
||||
l = __raw_readl(reg);
|
||||
if (enable)
|
||||
l &= ~(gpio_mask);
|
||||
else
|
||||
l |= gpio_mask;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
return;
|
||||
}
|
||||
__raw_writel(l, reg);
|
||||
}
|
||||
|
||||
static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable)
|
||||
{
|
||||
_enable_gpio_irqbank(bank, 1 << get_gpio_index(gpio), enable);
|
||||
}
|
||||
|
||||
int omap_request_gpio(int gpio)
|
||||
{
|
||||
struct gpio_bank *bank;
|
||||
|
||||
if (check_gpio(gpio) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
bank = get_gpio_bank(gpio);
|
||||
spin_lock(&bank->lock);
|
||||
if (unlikely(bank->reserved_map & (1 << get_gpio_index(gpio)))) {
|
||||
printk(KERN_ERR "omap-gpio: GPIO %d is already reserved!\n", gpio);
|
||||
dump_stack();
|
||||
spin_unlock(&bank->lock);
|
||||
return -1;
|
||||
}
|
||||
bank->reserved_map |= (1 << get_gpio_index(gpio));
|
||||
#ifdef CONFIG_ARCH_OMAP1510
|
||||
if (bank->method == METHOD_GPIO_1510) {
|
||||
u32 reg;
|
||||
|
||||
/* Claim the pin for the ARM */
|
||||
reg = bank->base + OMAP1510_GPIO_PIN_CONTROL;
|
||||
__raw_writel(__raw_readl(reg) | (1 << get_gpio_index(gpio)), reg);
|
||||
}
|
||||
#endif
|
||||
spin_unlock(&bank->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void omap_free_gpio(int gpio)
|
||||
{
|
||||
struct gpio_bank *bank;
|
||||
|
||||
if (check_gpio(gpio) < 0)
|
||||
return;
|
||||
bank = get_gpio_bank(gpio);
|
||||
spin_lock(&bank->lock);
|
||||
if (unlikely(!(bank->reserved_map & (1 << get_gpio_index(gpio))))) {
|
||||
printk(KERN_ERR "omap-gpio: GPIO %d wasn't reserved!\n", gpio);
|
||||
dump_stack();
|
||||
spin_unlock(&bank->lock);
|
||||
return;
|
||||
}
|
||||
bank->reserved_map &= ~(1 << get_gpio_index(gpio));
|
||||
_set_gpio_direction(bank, get_gpio_index(gpio), 1);
|
||||
_set_gpio_irqenable(bank, gpio, 0);
|
||||
_clear_gpio_irqstatus(bank, gpio);
|
||||
spin_unlock(&bank->lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to unmask the GPIO bank interrupt as soon as possible to
|
||||
* avoid missing GPIO interrupts for other lines in the bank.
|
||||
* Then we need to mask-read-clear-unmask the triggered GPIO lines
|
||||
* in the bank to avoid missing nested interrupts for a GPIO line.
|
||||
* If we wait to unmask individual GPIO lines in the bank after the
|
||||
* line's interrupt handler has been run, we may miss some nested
|
||||
* interrupts.
|
||||
*/
|
||||
static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
u32 isr_reg = 0;
|
||||
u32 isr;
|
||||
unsigned int gpio_irq;
|
||||
struct gpio_bank *bank;
|
||||
|
||||
desc->chip->ack(irq);
|
||||
|
||||
bank = (struct gpio_bank *) desc->data;
|
||||
if (bank->method == METHOD_MPUIO)
|
||||
isr_reg = bank->base + OMAP_MPUIO_GPIO_INT;
|
||||
#ifdef CONFIG_ARCH_OMAP1510
|
||||
if (bank->method == METHOD_GPIO_1510)
|
||||
isr_reg = bank->base + OMAP1510_GPIO_INT_STATUS;
|
||||
#endif
|
||||
#if defined(CONFIG_ARCH_OMAP16XX)
|
||||
if (bank->method == METHOD_GPIO_1610)
|
||||
isr_reg = bank->base + OMAP1610_GPIO_IRQSTATUS1;
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_OMAP730
|
||||
if (bank->method == METHOD_GPIO_730)
|
||||
isr_reg = bank->base + OMAP730_GPIO_INT_STATUS;
|
||||
#endif
|
||||
|
||||
isr = __raw_readl(isr_reg);
|
||||
_enable_gpio_irqbank(bank, isr, 0);
|
||||
_clear_gpio_irqbank(bank, isr);
|
||||
_enable_gpio_irqbank(bank, isr, 1);
|
||||
desc->chip->unmask(irq);
|
||||
|
||||
if (unlikely(!isr))
|
||||
return;
|
||||
|
||||
gpio_irq = bank->virtual_irq_start;
|
||||
for (; isr != 0; isr >>= 1, gpio_irq++) {
|
||||
struct irqdesc *d;
|
||||
if (!(isr & 1))
|
||||
continue;
|
||||
d = irq_desc + gpio_irq;
|
||||
d->handle(gpio_irq, d, regs);
|
||||
}
|
||||
}
|
||||
|
||||
static void gpio_ack_irq(unsigned int irq)
|
||||
{
|
||||
unsigned int gpio = irq - IH_GPIO_BASE;
|
||||
struct gpio_bank *bank = get_gpio_bank(gpio);
|
||||
|
||||
_clear_gpio_irqstatus(bank, gpio);
|
||||
}
|
||||
|
||||
static void gpio_mask_irq(unsigned int irq)
|
||||
{
|
||||
unsigned int gpio = irq - IH_GPIO_BASE;
|
||||
struct gpio_bank *bank = get_gpio_bank(gpio);
|
||||
|
||||
_set_gpio_irqenable(bank, gpio, 0);
|
||||
}
|
||||
|
||||
static void gpio_unmask_irq(unsigned int irq)
|
||||
{
|
||||
unsigned int gpio = irq - IH_GPIO_BASE;
|
||||
struct gpio_bank *bank = get_gpio_bank(gpio);
|
||||
|
||||
if (_get_gpio_edge_ctrl(bank, get_gpio_index(gpio)) == OMAP_GPIO_NO_EDGE) {
|
||||
printk(KERN_ERR "OMAP GPIO %d: trying to enable GPIO IRQ while no edge is set\n",
|
||||
gpio);
|
||||
_set_gpio_edge_ctrl(bank, get_gpio_index(gpio), OMAP_GPIO_RISING_EDGE);
|
||||
}
|
||||
_set_gpio_irqenable(bank, gpio, 1);
|
||||
}
|
||||
|
||||
static void mpuio_ack_irq(unsigned int irq)
|
||||
{
|
||||
/* The ISR is reset automatically, so do nothing here. */
|
||||
}
|
||||
|
||||
static void mpuio_mask_irq(unsigned int irq)
|
||||
{
|
||||
unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE);
|
||||
struct gpio_bank *bank = get_gpio_bank(gpio);
|
||||
|
||||
_set_gpio_irqenable(bank, gpio, 0);
|
||||
}
|
||||
|
||||
static void mpuio_unmask_irq(unsigned int irq)
|
||||
{
|
||||
unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE);
|
||||
struct gpio_bank *bank = get_gpio_bank(gpio);
|
||||
|
||||
_set_gpio_irqenable(bank, gpio, 1);
|
||||
}
|
||||
|
||||
static struct irqchip gpio_irq_chip = {
|
||||
.ack = gpio_ack_irq,
|
||||
.mask = gpio_mask_irq,
|
||||
.unmask = gpio_unmask_irq,
|
||||
};
|
||||
|
||||
static struct irqchip mpuio_irq_chip = {
|
||||
.ack = mpuio_ack_irq,
|
||||
.mask = mpuio_mask_irq,
|
||||
.unmask = mpuio_unmask_irq
|
||||
};
|
||||
|
||||
static int initialized = 0;
|
||||
|
||||
static int __init _omap_gpio_init(void)
|
||||
{
|
||||
int i;
|
||||
struct gpio_bank *bank;
|
||||
|
||||
initialized = 1;
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP1510
|
||||
if (cpu_is_omap1510()) {
|
||||
printk(KERN_INFO "OMAP1510 GPIO hardware\n");
|
||||
gpio_bank_count = 2;
|
||||
gpio_bank = gpio_bank_1510;
|
||||
}
|
||||
#endif
|
||||
#if defined(CONFIG_ARCH_OMAP16XX)
|
||||
if (cpu_is_omap16xx()) {
|
||||
int rev;
|
||||
|
||||
gpio_bank_count = 5;
|
||||
gpio_bank = gpio_bank_1610;
|
||||
rev = omap_readw(gpio_bank[1].base + OMAP1610_GPIO_REVISION);
|
||||
printk(KERN_INFO "OMAP GPIO hardware version %d.%d\n",
|
||||
(rev >> 4) & 0x0f, rev & 0x0f);
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_OMAP730
|
||||
if (cpu_is_omap730()) {
|
||||
printk(KERN_INFO "OMAP730 GPIO hardware\n");
|
||||
gpio_bank_count = 7;
|
||||
gpio_bank = gpio_bank_730;
|
||||
}
|
||||
#endif
|
||||
for (i = 0; i < gpio_bank_count; i++) {
|
||||
int j, gpio_count = 16;
|
||||
|
||||
bank = &gpio_bank[i];
|
||||
bank->reserved_map = 0;
|
||||
bank->base = IO_ADDRESS(bank->base);
|
||||
spin_lock_init(&bank->lock);
|
||||
if (bank->method == METHOD_MPUIO) {
|
||||
omap_writew(0xFFFF, OMAP_MPUIO_BASE + OMAP_MPUIO_GPIO_MASKIT);
|
||||
}
|
||||
#ifdef CONFIG_ARCH_OMAP1510
|
||||
if (bank->method == METHOD_GPIO_1510) {
|
||||
__raw_writew(0xffff, bank->base + OMAP1510_GPIO_INT_MASK);
|
||||
__raw_writew(0x0000, bank->base + OMAP1510_GPIO_INT_STATUS);
|
||||
}
|
||||
#endif
|
||||
#if defined(CONFIG_ARCH_OMAP16XX)
|
||||
if (bank->method == METHOD_GPIO_1610) {
|
||||
__raw_writew(0x0000, bank->base + OMAP1610_GPIO_IRQENABLE1);
|
||||
__raw_writew(0xffff, bank->base + OMAP1610_GPIO_IRQSTATUS1);
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_OMAP730
|
||||
if (bank->method == METHOD_GPIO_730) {
|
||||
__raw_writel(0xffffffff, bank->base + OMAP730_GPIO_INT_MASK);
|
||||
__raw_writel(0x00000000, bank->base + OMAP730_GPIO_INT_STATUS);
|
||||
|
||||
gpio_count = 32; /* 730 has 32-bit GPIOs */
|
||||
}
|
||||
#endif
|
||||
for (j = bank->virtual_irq_start;
|
||||
j < bank->virtual_irq_start + gpio_count; j++) {
|
||||
if (bank->method == METHOD_MPUIO)
|
||||
set_irq_chip(j, &mpuio_irq_chip);
|
||||
else
|
||||
set_irq_chip(j, &gpio_irq_chip);
|
||||
set_irq_handler(j, do_simple_IRQ);
|
||||
set_irq_flags(j, IRQF_VALID);
|
||||
}
|
||||
set_irq_chained_handler(bank->irq, gpio_irq_handler);
|
||||
set_irq_data(bank->irq, bank);
|
||||
}
|
||||
|
||||
/* Enable system clock for GPIO module.
|
||||
* The CAM_CLK_CTRL *is* really the right place. */
|
||||
if (cpu_is_omap1610() || cpu_is_omap1710())
|
||||
omap_writel(omap_readl(ULPD_CAM_CLK_CTRL) | 0x04, ULPD_CAM_CLK_CTRL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This may get called early from board specific init
|
||||
*/
|
||||
int omap_gpio_init(void)
|
||||
{
|
||||
if (!initialized)
|
||||
return _omap_gpio_init();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(omap_request_gpio);
|
||||
EXPORT_SYMBOL(omap_free_gpio);
|
||||
EXPORT_SYMBOL(omap_set_gpio_direction);
|
||||
EXPORT_SYMBOL(omap_set_gpio_dataout);
|
||||
EXPORT_SYMBOL(omap_get_gpio_datain);
|
||||
EXPORT_SYMBOL(omap_set_gpio_edge_ctrl);
|
||||
|
||||
arch_initcall(omap_gpio_init);
|
@ -1,685 +0,0 @@
|
||||
/*
|
||||
* linux/arch/arm/omap/mcbsp.c
|
||||
*
|
||||
* Copyright (C) 2004 Nokia Corporation
|
||||
* Author: Samuel Ortiz <samuel.ortiz@nokia.com>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Multichannel mode not supported.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <asm/delay.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
#include <asm/arch/dma.h>
|
||||
#include <asm/arch/mux.h>
|
||||
#include <asm/arch/irqs.h>
|
||||
#include <asm/arch/mcbsp.h>
|
||||
|
||||
#include <asm/hardware/clock.h>
|
||||
|
||||
#ifdef CONFIG_MCBSP_DEBUG
|
||||
#define DBG(x...) printk(x)
|
||||
#else
|
||||
#define DBG(x...) do { } while (0)
|
||||
#endif
|
||||
|
||||
struct omap_mcbsp {
|
||||
u32 io_base;
|
||||
u8 id;
|
||||
u8 free;
|
||||
omap_mcbsp_word_length rx_word_length;
|
||||
omap_mcbsp_word_length tx_word_length;
|
||||
|
||||
/* IRQ based TX/RX */
|
||||
int rx_irq;
|
||||
int tx_irq;
|
||||
|
||||
/* DMA stuff */
|
||||
u8 dma_rx_sync;
|
||||
short dma_rx_lch;
|
||||
u8 dma_tx_sync;
|
||||
short dma_tx_lch;
|
||||
|
||||
/* Completion queues */
|
||||
struct completion tx_irq_completion;
|
||||
struct completion rx_irq_completion;
|
||||
struct completion tx_dma_completion;
|
||||
struct completion rx_dma_completion;
|
||||
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
static struct omap_mcbsp mcbsp[OMAP_MAX_MCBSP_COUNT];
|
||||
static struct clk *mcbsp_dsp_ck = 0;
|
||||
static struct clk *mcbsp_api_ck = 0;
|
||||
|
||||
|
||||
static void omap_mcbsp_dump_reg(u8 id)
|
||||
{
|
||||
DBG("**** MCBSP%d regs ****\n", mcbsp[id].id);
|
||||
DBG("DRR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DRR2));
|
||||
DBG("DRR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DRR1));
|
||||
DBG("DXR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DXR2));
|
||||
DBG("DXR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DXR1));
|
||||
DBG("SPCR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SPCR2));
|
||||
DBG("SPCR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SPCR1));
|
||||
DBG("RCR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, RCR2));
|
||||
DBG("RCR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, RCR1));
|
||||
DBG("XCR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, XCR2));
|
||||
DBG("XCR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, XCR1));
|
||||
DBG("SRGR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SRGR2));
|
||||
DBG("SRGR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SRGR1));
|
||||
DBG("PCR0: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, PCR0));
|
||||
DBG("***********************\n");
|
||||
}
|
||||
|
||||
|
||||
static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
struct omap_mcbsp * mcbsp_tx = (struct omap_mcbsp *)(dev_id);
|
||||
|
||||
DBG("TX IRQ callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_tx->io_base, SPCR2));
|
||||
|
||||
complete(&mcbsp_tx->tx_irq_completion);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
struct omap_mcbsp * mcbsp_rx = (struct omap_mcbsp *)(dev_id);
|
||||
|
||||
DBG("RX IRQ callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_rx->io_base, SPCR2));
|
||||
|
||||
complete(&mcbsp_rx->rx_irq_completion);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
static void omap_mcbsp_tx_dma_callback(int lch, u16 ch_status, void *data)
|
||||
{
|
||||
struct omap_mcbsp * mcbsp_dma_tx = (struct omap_mcbsp *)(data);
|
||||
|
||||
DBG("TX DMA callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_dma_tx->io_base, SPCR2));
|
||||
|
||||
/* We can free the channels */
|
||||
omap_free_dma(mcbsp_dma_tx->dma_tx_lch);
|
||||
mcbsp_dma_tx->dma_tx_lch = -1;
|
||||
|
||||
complete(&mcbsp_dma_tx->tx_dma_completion);
|
||||
}
|
||||
|
||||
static void omap_mcbsp_rx_dma_callback(int lch, u16 ch_status, void *data)
|
||||
{
|
||||
struct omap_mcbsp * mcbsp_dma_rx = (struct omap_mcbsp *)(data);
|
||||
|
||||
DBG("RX DMA callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_dma_rx->io_base, SPCR2));
|
||||
|
||||
/* We can free the channels */
|
||||
omap_free_dma(mcbsp_dma_rx->dma_rx_lch);
|
||||
mcbsp_dma_rx->dma_rx_lch = -1;
|
||||
|
||||
complete(&mcbsp_dma_rx->rx_dma_completion);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* omap_mcbsp_config simply write a config to the
|
||||
* appropriate McBSP.
|
||||
* You either call this function or set the McBSP registers
|
||||
* by yourself before calling omap_mcbsp_start().
|
||||
*/
|
||||
|
||||
void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg * config)
|
||||
{
|
||||
u32 io_base = mcbsp[id].io_base;
|
||||
|
||||
DBG("OMAP-McBSP: McBSP%d io_base: 0x%8x\n", id+1, io_base);
|
||||
|
||||
/* We write the given config */
|
||||
OMAP_MCBSP_WRITE(io_base, SPCR2, config->spcr2);
|
||||
OMAP_MCBSP_WRITE(io_base, SPCR1, config->spcr1);
|
||||
OMAP_MCBSP_WRITE(io_base, RCR2, config->rcr2);
|
||||
OMAP_MCBSP_WRITE(io_base, RCR1, config->rcr1);
|
||||
OMAP_MCBSP_WRITE(io_base, XCR2, config->xcr2);
|
||||
OMAP_MCBSP_WRITE(io_base, XCR1, config->xcr1);
|
||||
OMAP_MCBSP_WRITE(io_base, SRGR2, config->srgr2);
|
||||
OMAP_MCBSP_WRITE(io_base, SRGR1, config->srgr1);
|
||||
OMAP_MCBSP_WRITE(io_base, MCR2, config->mcr2);
|
||||
OMAP_MCBSP_WRITE(io_base, MCR1, config->mcr1);
|
||||
OMAP_MCBSP_WRITE(io_base, PCR0, config->pcr0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int omap_mcbsp_check(unsigned int id)
|
||||
{
|
||||
if (cpu_is_omap730()) {
|
||||
if (id > OMAP_MAX_MCBSP_COUNT - 1) {
|
||||
printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cpu_is_omap1510() || cpu_is_omap1610() || cpu_is_omap1710()) {
|
||||
if (id > OMAP_MAX_MCBSP_COUNT) {
|
||||
printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define EN_XORPCK 1
|
||||
#define DSP_RSTCT2 0xe1008014
|
||||
|
||||
static void omap_mcbsp_dsp_request(void)
|
||||
{
|
||||
if (cpu_is_omap1510() || cpu_is_omap1610() || cpu_is_omap1710()) {
|
||||
omap_writew((omap_readw(ARM_RSTCT1) | (1 << 1) | (1 << 2)),
|
||||
ARM_RSTCT1);
|
||||
clk_enable(mcbsp_dsp_ck);
|
||||
clk_enable(mcbsp_api_ck);
|
||||
|
||||
/* enable 12MHz clock to mcbsp 1 & 3 */
|
||||
__raw_writew(__raw_readw(DSP_IDLECT2) | (1 << EN_XORPCK),
|
||||
DSP_IDLECT2);
|
||||
__raw_writew(__raw_readw(DSP_RSTCT2) | 1 | 1 << 1,
|
||||
DSP_RSTCT2);
|
||||
}
|
||||
}
|
||||
|
||||
static void omap_mcbsp_dsp_free(void)
|
||||
{
|
||||
/* Useless for now */
|
||||
}
|
||||
|
||||
|
||||
int omap_mcbsp_request(unsigned int id)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (omap_mcbsp_check(id) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* On 1510, 1610 and 1710, McBSP1 and McBSP3
|
||||
* are DSP public peripherals.
|
||||
*/
|
||||
if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3)
|
||||
omap_mcbsp_dsp_request();
|
||||
|
||||
spin_lock(&mcbsp[id].lock);
|
||||
if (!mcbsp[id].free) {
|
||||
printk (KERN_ERR "OMAP-McBSP: McBSP%d is currently in use\n", id + 1);
|
||||
spin_unlock(&mcbsp[id].lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
mcbsp[id].free = 0;
|
||||
spin_unlock(&mcbsp[id].lock);
|
||||
|
||||
/* We need to get IRQs here */
|
||||
err = request_irq(mcbsp[id].tx_irq, omap_mcbsp_tx_irq_handler, 0,
|
||||
"McBSP",
|
||||
(void *) (&mcbsp[id]));
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "OMAP-McBSP: Unable to request TX IRQ %d for McBSP%d\n",
|
||||
mcbsp[id].tx_irq, mcbsp[id].id);
|
||||
return err;
|
||||
}
|
||||
|
||||
init_completion(&(mcbsp[id].tx_irq_completion));
|
||||
|
||||
|
||||
err = request_irq(mcbsp[id].rx_irq, omap_mcbsp_rx_irq_handler, 0,
|
||||
"McBSP",
|
||||
(void *) (&mcbsp[id]));
|
||||
if (err != 0) {
|
||||
printk(KERN_ERR "OMAP-McBSP: Unable to request RX IRQ %d for McBSP%d\n",
|
||||
mcbsp[id].rx_irq, mcbsp[id].id);
|
||||
free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id]));
|
||||
return err;
|
||||
}
|
||||
|
||||
init_completion(&(mcbsp[id].rx_irq_completion));
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void omap_mcbsp_free(unsigned int id)
|
||||
{
|
||||
if (omap_mcbsp_check(id) < 0)
|
||||
return;
|
||||
|
||||
if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3)
|
||||
omap_mcbsp_dsp_free();
|
||||
|
||||
spin_lock(&mcbsp[id].lock);
|
||||
if (mcbsp[id].free) {
|
||||
printk (KERN_ERR "OMAP-McBSP: McBSP%d was not reserved\n", id + 1);
|
||||
spin_unlock(&mcbsp[id].lock);
|
||||
return;
|
||||
}
|
||||
|
||||
mcbsp[id].free = 1;
|
||||
spin_unlock(&mcbsp[id].lock);
|
||||
|
||||
/* Free IRQs */
|
||||
free_irq(mcbsp[id].rx_irq, (void *) (&mcbsp[id]));
|
||||
free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id]));
|
||||
}
|
||||
|
||||
/*
|
||||
* Here we start the McBSP, by enabling the sample
|
||||
* generator, both transmitter and receivers,
|
||||
* and the frame sync.
|
||||
*/
|
||||
void omap_mcbsp_start(unsigned int id)
|
||||
{
|
||||
u32 io_base;
|
||||
u16 w;
|
||||
|
||||
if (omap_mcbsp_check(id) < 0)
|
||||
return;
|
||||
|
||||
io_base = mcbsp[id].io_base;
|
||||
|
||||
mcbsp[id].rx_word_length = ((OMAP_MCBSP_READ(io_base, RCR1) >> 5) & 0x7);
|
||||
mcbsp[id].tx_word_length = ((OMAP_MCBSP_READ(io_base, XCR1) >> 5) & 0x7);
|
||||
|
||||
/* Start the sample generator */
|
||||
w = OMAP_MCBSP_READ(io_base, SPCR2);
|
||||
OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6));
|
||||
|
||||
/* Enable transmitter and receiver */
|
||||
w = OMAP_MCBSP_READ(io_base, SPCR2);
|
||||
OMAP_MCBSP_WRITE(io_base, SPCR2, w | 1);
|
||||
|
||||
w = OMAP_MCBSP_READ(io_base, SPCR1);
|
||||
OMAP_MCBSP_WRITE(io_base, SPCR1, w | 1);
|
||||
|
||||
udelay(100);
|
||||
|
||||
/* Start frame sync */
|
||||
w = OMAP_MCBSP_READ(io_base, SPCR2);
|
||||
OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7));
|
||||
|
||||
/* Dump McBSP Regs */
|
||||
omap_mcbsp_dump_reg(id);
|
||||
|
||||
}
|
||||
|
||||
void omap_mcbsp_stop(unsigned int id)
|
||||
{
|
||||
u32 io_base;
|
||||
u16 w;
|
||||
|
||||
if (omap_mcbsp_check(id) < 0)
|
||||
return;
|
||||
|
||||
io_base = mcbsp[id].io_base;
|
||||
|
||||
/* Reset transmitter */
|
||||
w = OMAP_MCBSP_READ(io_base, SPCR2);
|
||||
OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1));
|
||||
|
||||
/* Reset receiver */
|
||||
w = OMAP_MCBSP_READ(io_base, SPCR1);
|
||||
OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~(1));
|
||||
|
||||
/* Reset the sample rate generator */
|
||||
w = OMAP_MCBSP_READ(io_base, SPCR2);
|
||||
OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* IRQ based word transmission.
|
||||
*/
|
||||
void omap_mcbsp_xmit_word(unsigned int id, u32 word)
|
||||
{
|
||||
u32 io_base;
|
||||
omap_mcbsp_word_length word_length = mcbsp[id].tx_word_length;
|
||||
|
||||
if (omap_mcbsp_check(id) < 0)
|
||||
return;
|
||||
|
||||
io_base = mcbsp[id].io_base;
|
||||
|
||||
wait_for_completion(&(mcbsp[id].tx_irq_completion));
|
||||
|
||||
if (word_length > OMAP_MCBSP_WORD_16)
|
||||
OMAP_MCBSP_WRITE(io_base, DXR2, word >> 16);
|
||||
OMAP_MCBSP_WRITE(io_base, DXR1, word & 0xffff);
|
||||
}
|
||||
|
||||
u32 omap_mcbsp_recv_word(unsigned int id)
|
||||
{
|
||||
u32 io_base;
|
||||
u16 word_lsb, word_msb = 0;
|
||||
omap_mcbsp_word_length word_length = mcbsp[id].rx_word_length;
|
||||
|
||||
if (omap_mcbsp_check(id) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
io_base = mcbsp[id].io_base;
|
||||
|
||||
wait_for_completion(&(mcbsp[id].rx_irq_completion));
|
||||
|
||||
if (word_length > OMAP_MCBSP_WORD_16)
|
||||
word_msb = OMAP_MCBSP_READ(io_base, DRR2);
|
||||
word_lsb = OMAP_MCBSP_READ(io_base, DRR1);
|
||||
|
||||
return (word_lsb | (word_msb << 16));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Simple DMA based buffer rx/tx routines.
|
||||
* Nothing fancy, just a single buffer tx/rx through DMA.
|
||||
* The DMA resources are released once the transfer is done.
|
||||
* For anything fancier, you should use your own customized DMA
|
||||
* routines and callbacks.
|
||||
*/
|
||||
int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int length)
|
||||
{
|
||||
int dma_tx_ch;
|
||||
|
||||
if (omap_mcbsp_check(id) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (omap_request_dma(mcbsp[id].dma_tx_sync, "McBSP TX", omap_mcbsp_tx_dma_callback,
|
||||
&mcbsp[id],
|
||||
&dma_tx_ch)) {
|
||||
printk("OMAP-McBSP: Unable to request DMA channel for McBSP%d TX. Trying IRQ based TX\n", id+1);
|
||||
return -EAGAIN;
|
||||
}
|
||||
mcbsp[id].dma_tx_lch = dma_tx_ch;
|
||||
|
||||
DBG("TX DMA on channel %d\n", dma_tx_ch);
|
||||
|
||||
init_completion(&(mcbsp[id].tx_dma_completion));
|
||||
|
||||
omap_set_dma_transfer_params(mcbsp[id].dma_tx_lch,
|
||||
OMAP_DMA_DATA_TYPE_S16,
|
||||
length >> 1, 1,
|
||||
OMAP_DMA_SYNC_ELEMENT);
|
||||
|
||||
omap_set_dma_dest_params(mcbsp[id].dma_tx_lch,
|
||||
OMAP_DMA_PORT_TIPB,
|
||||
OMAP_DMA_AMODE_CONSTANT,
|
||||
mcbsp[id].io_base + OMAP_MCBSP_REG_DXR1);
|
||||
|
||||
omap_set_dma_src_params(mcbsp[id].dma_tx_lch,
|
||||
OMAP_DMA_PORT_EMIFF,
|
||||
OMAP_DMA_AMODE_POST_INC,
|
||||
buffer);
|
||||
|
||||
omap_start_dma(mcbsp[id].dma_tx_lch);
|
||||
wait_for_completion(&(mcbsp[id].tx_dma_completion));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, unsigned int length)
|
||||
{
|
||||
int dma_rx_ch;
|
||||
|
||||
if (omap_mcbsp_check(id) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (omap_request_dma(mcbsp[id].dma_rx_sync, "McBSP RX", omap_mcbsp_rx_dma_callback,
|
||||
&mcbsp[id],
|
||||
&dma_rx_ch)) {
|
||||
printk("Unable to request DMA channel for McBSP%d RX. Trying IRQ based RX\n", id+1);
|
||||
return -EAGAIN;
|
||||
}
|
||||
mcbsp[id].dma_rx_lch = dma_rx_ch;
|
||||
|
||||
DBG("RX DMA on channel %d\n", dma_rx_ch);
|
||||
|
||||
init_completion(&(mcbsp[id].rx_dma_completion));
|
||||
|
||||
omap_set_dma_transfer_params(mcbsp[id].dma_rx_lch,
|
||||
OMAP_DMA_DATA_TYPE_S16,
|
||||
length >> 1, 1,
|
||||
OMAP_DMA_SYNC_ELEMENT);
|
||||
|
||||
omap_set_dma_src_params(mcbsp[id].dma_rx_lch,
|
||||
OMAP_DMA_PORT_TIPB,
|
||||
OMAP_DMA_AMODE_CONSTANT,
|
||||
mcbsp[id].io_base + OMAP_MCBSP_REG_DRR1);
|
||||
|
||||
omap_set_dma_dest_params(mcbsp[id].dma_rx_lch,
|
||||
OMAP_DMA_PORT_EMIFF,
|
||||
OMAP_DMA_AMODE_POST_INC,
|
||||
buffer);
|
||||
|
||||
omap_start_dma(mcbsp[id].dma_rx_lch);
|
||||
wait_for_completion(&(mcbsp[id].rx_dma_completion));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SPI wrapper.
|
||||
* Since SPI setup is much simpler than the generic McBSP one,
|
||||
* this wrapper just need an omap_mcbsp_spi_cfg structure as an input.
|
||||
* Once this is done, you can call omap_mcbsp_start().
|
||||
*/
|
||||
void omap_mcbsp_set_spi_mode(unsigned int id, const struct omap_mcbsp_spi_cfg * spi_cfg)
|
||||
{
|
||||
struct omap_mcbsp_reg_cfg mcbsp_cfg;
|
||||
|
||||
if (omap_mcbsp_check(id) < 0)
|
||||
return;
|
||||
|
||||
memset(&mcbsp_cfg, 0, sizeof(struct omap_mcbsp_reg_cfg));
|
||||
|
||||
/* SPI has only one frame */
|
||||
mcbsp_cfg.rcr1 |= (RWDLEN1(spi_cfg->word_length) | RFRLEN1(0));
|
||||
mcbsp_cfg.xcr1 |= (XWDLEN1(spi_cfg->word_length) | XFRLEN1(0));
|
||||
|
||||
/* Clock stop mode */
|
||||
if (spi_cfg->clk_stp_mode == OMAP_MCBSP_CLK_STP_MODE_NO_DELAY)
|
||||
mcbsp_cfg.spcr1 |= (1 << 12);
|
||||
else
|
||||
mcbsp_cfg.spcr1 |= (3 << 11);
|
||||
|
||||
/* Set clock parities */
|
||||
if (spi_cfg->rx_clock_polarity == OMAP_MCBSP_CLK_RISING)
|
||||
mcbsp_cfg.pcr0 |= CLKRP;
|
||||
else
|
||||
mcbsp_cfg.pcr0 &= ~CLKRP;
|
||||
|
||||
if (spi_cfg->tx_clock_polarity == OMAP_MCBSP_CLK_RISING)
|
||||
mcbsp_cfg.pcr0 &= ~CLKXP;
|
||||
else
|
||||
mcbsp_cfg.pcr0 |= CLKXP;
|
||||
|
||||
/* Set SCLKME to 0 and CLKSM to 1 */
|
||||
mcbsp_cfg.pcr0 &= ~SCLKME;
|
||||
mcbsp_cfg.srgr2 |= CLKSM;
|
||||
|
||||
/* Set FSXP */
|
||||
if (spi_cfg->fsx_polarity == OMAP_MCBSP_FS_ACTIVE_HIGH)
|
||||
mcbsp_cfg.pcr0 &= ~FSXP;
|
||||
else
|
||||
mcbsp_cfg.pcr0 |= FSXP;
|
||||
|
||||
if (spi_cfg->spi_mode == OMAP_MCBSP_SPI_MASTER) {
|
||||
mcbsp_cfg.pcr0 |= CLKXM;
|
||||
mcbsp_cfg.srgr1 |= CLKGDV(spi_cfg->clk_div -1);
|
||||
mcbsp_cfg.pcr0 |= FSXM;
|
||||
mcbsp_cfg.srgr2 &= ~FSGM;
|
||||
mcbsp_cfg.xcr2 |= XDATDLY(1);
|
||||
mcbsp_cfg.rcr2 |= RDATDLY(1);
|
||||
}
|
||||
else {
|
||||
mcbsp_cfg.pcr0 &= ~CLKXM;
|
||||
mcbsp_cfg.srgr1 |= CLKGDV(1);
|
||||
mcbsp_cfg.pcr0 &= ~FSXM;
|
||||
mcbsp_cfg.xcr2 &= ~XDATDLY(3);
|
||||
mcbsp_cfg.rcr2 &= ~RDATDLY(3);
|
||||
}
|
||||
|
||||
mcbsp_cfg.xcr2 &= ~XPHASE;
|
||||
mcbsp_cfg.rcr2 &= ~RPHASE;
|
||||
|
||||
omap_mcbsp_config(id, &mcbsp_cfg);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* McBSP1 and McBSP3 are directly mapped on 1610 and 1510.
|
||||
* 730 has only 2 McBSP, and both of them are MPU peripherals.
|
||||
*/
|
||||
struct omap_mcbsp_info {
|
||||
u32 virt_base;
|
||||
u8 dma_rx_sync, dma_tx_sync;
|
||||
u16 rx_irq, tx_irq;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP730
|
||||
static const struct omap_mcbsp_info mcbsp_730[] = {
|
||||
[0] = { .virt_base = io_p2v(OMAP730_MCBSP1_BASE),
|
||||
.dma_rx_sync = OMAP_DMA_MCBSP1_RX,
|
||||
.dma_tx_sync = OMAP_DMA_MCBSP1_TX,
|
||||
.rx_irq = INT_730_McBSP1RX,
|
||||
.tx_irq = INT_730_McBSP1TX },
|
||||
[1] = { .virt_base = io_p2v(OMAP730_MCBSP2_BASE),
|
||||
.dma_rx_sync = OMAP_DMA_MCBSP3_RX,
|
||||
.dma_tx_sync = OMAP_DMA_MCBSP3_TX,
|
||||
.rx_irq = INT_730_McBSP2RX,
|
||||
.tx_irq = INT_730_McBSP2TX },
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP1510
|
||||
static const struct omap_mcbsp_info mcbsp_1510[] = {
|
||||
[0] = { .virt_base = OMAP1510_MCBSP1_BASE,
|
||||
.dma_rx_sync = OMAP_DMA_MCBSP1_RX,
|
||||
.dma_tx_sync = OMAP_DMA_MCBSP1_TX,
|
||||
.rx_irq = INT_McBSP1RX,
|
||||
.tx_irq = INT_McBSP1TX },
|
||||
[1] = { .virt_base = io_p2v(OMAP1510_MCBSP2_BASE),
|
||||
.dma_rx_sync = OMAP_DMA_MCBSP2_RX,
|
||||
.dma_tx_sync = OMAP_DMA_MCBSP2_TX,
|
||||
.rx_irq = INT_1510_SPI_RX,
|
||||
.tx_irq = INT_1510_SPI_TX },
|
||||
[2] = { .virt_base = OMAP1510_MCBSP3_BASE,
|
||||
.dma_rx_sync = OMAP_DMA_MCBSP3_RX,
|
||||
.dma_tx_sync = OMAP_DMA_MCBSP3_TX,
|
||||
.rx_irq = INT_McBSP3RX,
|
||||
.tx_irq = INT_McBSP3TX },
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ARCH_OMAP16XX)
|
||||
static const struct omap_mcbsp_info mcbsp_1610[] = {
|
||||
[0] = { .virt_base = OMAP1610_MCBSP1_BASE,
|
||||
.dma_rx_sync = OMAP_DMA_MCBSP1_RX,
|
||||
.dma_tx_sync = OMAP_DMA_MCBSP1_TX,
|
||||
.rx_irq = INT_McBSP1RX,
|
||||
.tx_irq = INT_McBSP1TX },
|
||||
[1] = { .virt_base = io_p2v(OMAP1610_MCBSP2_BASE),
|
||||
.dma_rx_sync = OMAP_DMA_MCBSP2_RX,
|
||||
.dma_tx_sync = OMAP_DMA_MCBSP2_TX,
|
||||
.rx_irq = INT_1610_McBSP2_RX,
|
||||
.tx_irq = INT_1610_McBSP2_TX },
|
||||
[2] = { .virt_base = OMAP1610_MCBSP3_BASE,
|
||||
.dma_rx_sync = OMAP_DMA_MCBSP3_RX,
|
||||
.dma_tx_sync = OMAP_DMA_MCBSP3_TX,
|
||||
.rx_irq = INT_McBSP3RX,
|
||||
.tx_irq = INT_McBSP3TX },
|
||||
};
|
||||
#endif
|
||||
|
||||
static int __init omap_mcbsp_init(void)
|
||||
{
|
||||
int mcbsp_count = 0, i;
|
||||
static const struct omap_mcbsp_info *mcbsp_info;
|
||||
|
||||
printk("Initializing OMAP McBSP system\n");
|
||||
|
||||
mcbsp_dsp_ck = clk_get(0, "dsp_ck");
|
||||
if (IS_ERR(mcbsp_dsp_ck)) {
|
||||
printk(KERN_ERR "mcbsp: could not acquire dsp_ck handle.\n");
|
||||
return PTR_ERR(mcbsp_dsp_ck);
|
||||
}
|
||||
mcbsp_api_ck = clk_get(0, "api_ck");
|
||||
if (IS_ERR(mcbsp_dsp_ck)) {
|
||||
printk(KERN_ERR "mcbsp: could not acquire api_ck handle.\n");
|
||||
return PTR_ERR(mcbsp_api_ck);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP730
|
||||
if (cpu_is_omap730()) {
|
||||
mcbsp_info = mcbsp_730;
|
||||
mcbsp_count = ARRAY_SIZE(mcbsp_730);
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_OMAP1510
|
||||
if (cpu_is_omap1510()) {
|
||||
mcbsp_info = mcbsp_1510;
|
||||
mcbsp_count = ARRAY_SIZE(mcbsp_1510);
|
||||
}
|
||||
#endif
|
||||
#if defined(CONFIG_ARCH_OMAP16XX)
|
||||
if (cpu_is_omap1610() || cpu_is_omap1710()) {
|
||||
mcbsp_info = mcbsp_1610;
|
||||
mcbsp_count = ARRAY_SIZE(mcbsp_1610);
|
||||
}
|
||||
#endif
|
||||
for (i = 0; i < OMAP_MAX_MCBSP_COUNT ; i++) {
|
||||
if (i >= mcbsp_count) {
|
||||
mcbsp[i].io_base = 0;
|
||||
mcbsp[i].free = 0;
|
||||
continue;
|
||||
}
|
||||
mcbsp[i].id = i + 1;
|
||||
mcbsp[i].free = 1;
|
||||
mcbsp[i].dma_tx_lch = -1;
|
||||
mcbsp[i].dma_rx_lch = -1;
|
||||
|
||||
mcbsp[i].io_base = mcbsp_info[i].virt_base;
|
||||
mcbsp[i].tx_irq = mcbsp_info[i].tx_irq;
|
||||
mcbsp[i].rx_irq = mcbsp_info[i].rx_irq;
|
||||
mcbsp[i].dma_rx_sync = mcbsp_info[i].dma_rx_sync;
|
||||
mcbsp[i].dma_tx_sync = mcbsp_info[i].dma_tx_sync;
|
||||
spin_lock_init(&mcbsp[i].lock);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
arch_initcall(omap_mcbsp_init);
|
||||
|
||||
EXPORT_SYMBOL(omap_mcbsp_config);
|
||||
EXPORT_SYMBOL(omap_mcbsp_request);
|
||||
EXPORT_SYMBOL(omap_mcbsp_free);
|
||||
EXPORT_SYMBOL(omap_mcbsp_start);
|
||||
EXPORT_SYMBOL(omap_mcbsp_stop);
|
||||
EXPORT_SYMBOL(omap_mcbsp_xmit_word);
|
||||
EXPORT_SYMBOL(omap_mcbsp_recv_word);
|
||||
EXPORT_SYMBOL(omap_mcbsp_xmit_buffer);
|
||||
EXPORT_SYMBOL(omap_mcbsp_recv_buffer);
|
||||
EXPORT_SYMBOL(omap_mcbsp_set_spi_mode);
|
@ -1,163 +0,0 @@
|
||||
/*
|
||||
* linux/arch/arm/mach-omap/mux.c
|
||||
*
|
||||
* Utility to set the Omap MUX and PULL_DWN registers from a table in mux.h
|
||||
*
|
||||
* Copyright (C) 2003 Nokia Corporation
|
||||
*
|
||||
* Written by Tony Lindgren <tony.lindgren@nokia.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#define __MUX_C__
|
||||
#include <asm/arch/mux.h>
|
||||
|
||||
#ifdef CONFIG_OMAP_MUX
|
||||
|
||||
/*
|
||||
* Sets the Omap MUX and PULL_DWN registers based on the table
|
||||
*/
|
||||
int __init_or_module
|
||||
omap_cfg_reg(const reg_cfg_t reg_cfg)
|
||||
{
|
||||
static DEFINE_SPINLOCK(mux_spin_lock);
|
||||
|
||||
unsigned long flags;
|
||||
reg_cfg_set *cfg;
|
||||
unsigned int reg_orig = 0, reg = 0, pu_pd_orig = 0, pu_pd = 0,
|
||||
pull_orig = 0, pull = 0;
|
||||
unsigned int mask, warn = 0;
|
||||
|
||||
if (reg_cfg > ARRAY_SIZE(reg_cfg_table)) {
|
||||
printk(KERN_ERR "MUX: reg_cfg %d\n", reg_cfg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cfg = ®_cfg_table[reg_cfg];
|
||||
|
||||
/*
|
||||
* We do a pretty long section here with lock on, but pin muxing
|
||||
* should only happen on driver init for each driver, so it's not time
|
||||
* critical.
|
||||
*/
|
||||
spin_lock_irqsave(&mux_spin_lock, flags);
|
||||
|
||||
/* Check the mux register in question */
|
||||
if (cfg->mux_reg) {
|
||||
unsigned tmp1, tmp2;
|
||||
|
||||
reg_orig = omap_readl(cfg->mux_reg);
|
||||
|
||||
/* The mux registers always seem to be 3 bits long */
|
||||
mask = (0x7 << cfg->mask_offset);
|
||||
tmp1 = reg_orig & mask;
|
||||
reg = reg_orig & ~mask;
|
||||
|
||||
tmp2 = (cfg->mask << cfg->mask_offset);
|
||||
reg |= tmp2;
|
||||
|
||||
if (tmp1 != tmp2)
|
||||
warn = 1;
|
||||
|
||||
omap_writel(reg, cfg->mux_reg);
|
||||
}
|
||||
|
||||
/* Check for pull up or pull down selection on 1610 */
|
||||
if (!cpu_is_omap1510()) {
|
||||
if (cfg->pu_pd_reg && cfg->pull_val) {
|
||||
pu_pd_orig = omap_readl(cfg->pu_pd_reg);
|
||||
mask = 1 << cfg->pull_bit;
|
||||
|
||||
if (cfg->pu_pd_val) {
|
||||
if (!(pu_pd_orig & mask))
|
||||
warn = 1;
|
||||
/* Use pull up */
|
||||
pu_pd = pu_pd_orig | mask;
|
||||
} else {
|
||||
if (pu_pd_orig & mask)
|
||||
warn = 1;
|
||||
/* Use pull down */
|
||||
pu_pd = pu_pd_orig & ~mask;
|
||||
}
|
||||
omap_writel(pu_pd, cfg->pu_pd_reg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for an associated pull down register */
|
||||
if (cfg->pull_reg) {
|
||||
pull_orig = omap_readl(cfg->pull_reg);
|
||||
mask = 1 << cfg->pull_bit;
|
||||
|
||||
if (cfg->pull_val) {
|
||||
if (pull_orig & mask)
|
||||
warn = 1;
|
||||
/* Low bit = pull enabled */
|
||||
pull = pull_orig & ~mask;
|
||||
} else {
|
||||
if (!(pull_orig & mask))
|
||||
warn = 1;
|
||||
/* High bit = pull disabled */
|
||||
pull = pull_orig | mask;
|
||||
}
|
||||
|
||||
omap_writel(pull, cfg->pull_reg);
|
||||
}
|
||||
|
||||
if (warn) {
|
||||
#ifdef CONFIG_OMAP_MUX_WARNINGS
|
||||
printk(KERN_WARNING "MUX: initialized %s\n", cfg->name);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OMAP_MUX_DEBUG
|
||||
if (cfg->debug || warn) {
|
||||
printk("MUX: Setting register %s\n", cfg->name);
|
||||
printk(" %s (0x%08x) = 0x%08x -> 0x%08x\n",
|
||||
cfg->mux_reg_name, cfg->mux_reg, reg_orig, reg);
|
||||
|
||||
if (!cpu_is_omap1510()) {
|
||||
if (cfg->pu_pd_reg && cfg->pull_val) {
|
||||
printk(" %s (0x%08x) = 0x%08x -> 0x%08x\n",
|
||||
cfg->pu_pd_name, cfg->pu_pd_reg,
|
||||
pu_pd_orig, pu_pd);
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg->pull_reg)
|
||||
printk(" %s (0x%08x) = 0x%08x -> 0x%08x\n",
|
||||
cfg->pull_name, cfg->pull_reg, pull_orig, pull);
|
||||
}
|
||||
#endif
|
||||
|
||||
spin_unlock_irqrestore(&mux_spin_lock, flags);
|
||||
|
||||
#ifdef CONFIG_OMAP_MUX_ERRORS
|
||||
return warn ? -ETXTBSY : 0;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(omap_cfg_reg);
|
||||
|
||||
#endif /* CONFIG_OMAP_MUX */
|
@ -1,114 +0,0 @@
|
||||
/*
|
||||
* linux/arch/arm/mach-omap/ocpi.c
|
||||
*
|
||||
* Minimal OCP bus support for omap16xx
|
||||
*
|
||||
* Copyright (C) 2003 - 2005 Nokia Corporation
|
||||
* Written by Tony Lindgren <tony@atomide.com>
|
||||
*
|
||||
* Modified for clock framework by Paul Mundt <paul.mundt@nokia.com>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/hardware/clock.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
|
||||
#define OCPI_BASE 0xfffec320
|
||||
#define OCPI_FAULT (OCPI_BASE + 0x00)
|
||||
#define OCPI_CMD_FAULT (OCPI_BASE + 0x04)
|
||||
#define OCPI_SINT0 (OCPI_BASE + 0x08)
|
||||
#define OCPI_TABORT (OCPI_BASE + 0x0c)
|
||||
#define OCPI_SINT1 (OCPI_BASE + 0x10)
|
||||
#define OCPI_PROT (OCPI_BASE + 0x14)
|
||||
#define OCPI_SEC (OCPI_BASE + 0x18)
|
||||
|
||||
/* USB OHCI OCPI access error registers */
|
||||
#define HOSTUEADDR 0xfffba0e0
|
||||
#define HOSTUESTATUS 0xfffba0e4
|
||||
|
||||
static struct clk *ocpi_ck;
|
||||
|
||||
/*
|
||||
* Enables device access to OMAP buses via the OCPI bridge
|
||||
* FIXME: Add locking
|
||||
*/
|
||||
int ocpi_enable(void)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
if (!cpu_is_omap16xx())
|
||||
return -ENODEV;
|
||||
|
||||
/* Make sure there's clock for OCPI */
|
||||
clk_enable(ocpi_ck);
|
||||
|
||||
/* Enable access for OHCI in OCPI */
|
||||
val = omap_readl(OCPI_PROT);
|
||||
val &= ~0xff;
|
||||
//val &= (1 << 0); /* Allow access only to EMIFS */
|
||||
omap_writel(val, OCPI_PROT);
|
||||
|
||||
val = omap_readl(OCPI_SEC);
|
||||
val &= ~0xff;
|
||||
omap_writel(val, OCPI_SEC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ocpi_enable);
|
||||
|
||||
static int __init omap_ocpi_init(void)
|
||||
{
|
||||
if (!cpu_is_omap16xx())
|
||||
return -ENODEV;
|
||||
|
||||
ocpi_ck = clk_get(NULL, "l3_ocpi_ck");
|
||||
if (IS_ERR(ocpi_ck))
|
||||
return PTR_ERR(ocpi_ck);
|
||||
|
||||
clk_use(ocpi_ck);
|
||||
ocpi_enable();
|
||||
printk("OMAP OCPI interconnect driver loaded\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit omap_ocpi_exit(void)
|
||||
{
|
||||
/* REVISIT: Disable OCPI */
|
||||
|
||||
if (!cpu_is_omap16xx())
|
||||
return;
|
||||
|
||||
clk_unuse(ocpi_ck);
|
||||
clk_put(ocpi_ck);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");
|
||||
MODULE_DESCRIPTION("OMAP OCPI bus controller module");
|
||||
MODULE_LICENSE("GPL");
|
||||
module_init(omap_ocpi_init);
|
||||
module_exit(omap_ocpi_exit);
|
@ -1,632 +0,0 @@
|
||||
/*
|
||||
* linux/arch/arm/mach-omap/pm.c
|
||||
*
|
||||
* OMAP Power Management Routines
|
||||
*
|
||||
* Original code for the SA11x0:
|
||||
* Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
|
||||
*
|
||||
* Modified for the PXA250 by Nicolas Pitre:
|
||||
* Copyright (c) 2002 Monta Vista Software, Inc.
|
||||
*
|
||||
* Modified for the OMAP1510 by David Singleton:
|
||||
* Copyright (c) 2002 Monta Vista Software, Inc.
|
||||
*
|
||||
* Cleanup 2004 for OMAP1510/1610 by Dirk Behme <dirk.behme@de.bosch.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/pm.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/pm.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/mach/time.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
#include <asm/arch/omap16xx.h>
|
||||
#include <asm/arch/pm.h>
|
||||
#include <asm/arch/mux.h>
|
||||
#include <asm/arch/tc.h>
|
||||
#include <asm/arch/tps65010.h>
|
||||
|
||||
#include "clock.h"
|
||||
|
||||
static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE];
|
||||
static unsigned short ulpd_sleep_save[ULPD_SLEEP_SAVE_SIZE];
|
||||
static unsigned int mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_SIZE];
|
||||
static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE];
|
||||
|
||||
/*
|
||||
* Let's power down on idle, but only if we are really
|
||||
* idle, because once we start down the path of
|
||||
* going idle we continue to do idle even if we get
|
||||
* a clock tick interrupt . .
|
||||
*/
|
||||
void omap_pm_idle(void)
|
||||
{
|
||||
int (*func_ptr)(void) = 0;
|
||||
unsigned int mask32 = 0;
|
||||
|
||||
/*
|
||||
* If the DSP is being used let's just idle the CPU, the overhead
|
||||
* to wake up from Big Sleep is big, milliseconds versus micro
|
||||
* seconds for wait for interrupt.
|
||||
*/
|
||||
|
||||
local_irq_disable();
|
||||
local_fiq_disable();
|
||||
if (need_resched()) {
|
||||
local_fiq_enable();
|
||||
local_irq_enable();
|
||||
return;
|
||||
}
|
||||
mask32 = omap_readl(ARM_SYSST);
|
||||
|
||||
/*
|
||||
* Since an interrupt may set up a timer, we don't want to
|
||||
* reprogram the hardware timer with interrupts enabled.
|
||||
* Re-enable interrupts only after returning from idle.
|
||||
*/
|
||||
timer_dyn_reprogram();
|
||||
|
||||
if ((mask32 & DSP_IDLE) == 0) {
|
||||
__asm__ volatile ("mcr p15, 0, r0, c7, c0, 4");
|
||||
} else {
|
||||
|
||||
if (cpu_is_omap1510()) {
|
||||
func_ptr = (void *)(OMAP1510_SRAM_IDLE_SUSPEND);
|
||||
} else if (cpu_is_omap1610() || cpu_is_omap1710()) {
|
||||
func_ptr = (void *)(OMAP1610_SRAM_IDLE_SUSPEND);
|
||||
} else if (cpu_is_omap5912()) {
|
||||
func_ptr = (void *)(OMAP5912_SRAM_IDLE_SUSPEND);
|
||||
}
|
||||
|
||||
func_ptr();
|
||||
}
|
||||
local_fiq_enable();
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
/*
|
||||
* Configuration of the wakeup event is board specific. For the
|
||||
* moment we put it into this helper function. Later it may move
|
||||
* to board specific files.
|
||||
*/
|
||||
static void omap_pm_wakeup_setup(void)
|
||||
{
|
||||
/*
|
||||
* Enable ARM XOR clock and release peripheral from reset by
|
||||
* writing 1 to PER_EN bit in ARM_RSTCT2, this is required
|
||||
* for UART configuration to use UART2 to wake up.
|
||||
*/
|
||||
|
||||
omap_writel(omap_readl(ARM_IDLECT2) | ENABLE_XORCLK, ARM_IDLECT2);
|
||||
omap_writel(omap_readl(ARM_RSTCT2) | PER_EN, ARM_RSTCT2);
|
||||
omap_writew(MODEM_32K_EN, ULPD_CLOCK_CTRL);
|
||||
|
||||
/*
|
||||
* Turn off all interrupts except L1-2nd level cascade,
|
||||
* and the L2 wakeup interrupts: keypad and UART2.
|
||||
*/
|
||||
|
||||
omap_writel(~IRQ_LEVEL2, OMAP_IH1_MIR);
|
||||
|
||||
if (cpu_is_omap1510()) {
|
||||
omap_writel(~(IRQ_UART2 | IRQ_KEYBOARD), OMAP_IH2_MIR);
|
||||
}
|
||||
|
||||
if (cpu_is_omap16xx()) {
|
||||
omap_writel(~(IRQ_UART2 | IRQ_KEYBOARD), OMAP_IH2_0_MIR);
|
||||
|
||||
omap_writel(~0x0, OMAP_IH2_1_MIR);
|
||||
omap_writel(~0x0, OMAP_IH2_2_MIR);
|
||||
omap_writel(~0x0, OMAP_IH2_3_MIR);
|
||||
}
|
||||
|
||||
/* New IRQ agreement */
|
||||
omap_writel(1, OMAP_IH1_CONTROL);
|
||||
|
||||
/* external PULL to down, bit 22 = 0 */
|
||||
omap_writel(omap_readl(PULL_DWN_CTRL_2) & ~(1<<22), PULL_DWN_CTRL_2);
|
||||
}
|
||||
|
||||
void omap_pm_suspend(void)
|
||||
{
|
||||
unsigned int mask32 = 0;
|
||||
unsigned long arg0 = 0, arg1 = 0;
|
||||
int (*func_ptr)(unsigned short, unsigned short) = 0;
|
||||
unsigned short save_dsp_idlect2;
|
||||
|
||||
printk("PM: OMAP%x is entering deep sleep now ...\n", system_rev);
|
||||
|
||||
if (machine_is_omap_osk()) {
|
||||
/* Stop LED1 (D9) blink */
|
||||
tps65010_set_led(LED1, OFF);
|
||||
}
|
||||
|
||||
/*
|
||||
* Step 1: turn off interrupts
|
||||
*/
|
||||
|
||||
local_irq_disable();
|
||||
local_fiq_disable();
|
||||
|
||||
/*
|
||||
* Step 2: save registers
|
||||
*
|
||||
* The omap is a strange/beautiful device. The caches, memory
|
||||
* and register state are preserved across power saves.
|
||||
* We have to save and restore very little register state to
|
||||
* idle the omap.
|
||||
*
|
||||
* Save interrupt, MPUI, ARM and UPLD control registers.
|
||||
*/
|
||||
|
||||
if (cpu_is_omap1510()) {
|
||||
MPUI1510_SAVE(OMAP_IH1_MIR);
|
||||
MPUI1510_SAVE(OMAP_IH2_MIR);
|
||||
MPUI1510_SAVE(MPUI_CTRL);
|
||||
MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG);
|
||||
MPUI1510_SAVE(MPUI_DSP_API_CONFIG);
|
||||
MPUI1510_SAVE(EMIFS_CONFIG);
|
||||
MPUI1510_SAVE(EMIFF_SDRAM_CONFIG);
|
||||
} else if (cpu_is_omap16xx()) {
|
||||
MPUI1610_SAVE(OMAP_IH1_MIR);
|
||||
MPUI1610_SAVE(OMAP_IH2_0_MIR);
|
||||
MPUI1610_SAVE(OMAP_IH2_1_MIR);
|
||||
MPUI1610_SAVE(OMAP_IH2_2_MIR);
|
||||
MPUI1610_SAVE(OMAP_IH2_3_MIR);
|
||||
MPUI1610_SAVE(MPUI_CTRL);
|
||||
MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG);
|
||||
MPUI1610_SAVE(MPUI_DSP_API_CONFIG);
|
||||
MPUI1610_SAVE(EMIFS_CONFIG);
|
||||
MPUI1610_SAVE(EMIFF_SDRAM_CONFIG);
|
||||
}
|
||||
|
||||
ARM_SAVE(ARM_CKCTL);
|
||||
ARM_SAVE(ARM_IDLECT1);
|
||||
ARM_SAVE(ARM_IDLECT2);
|
||||
ARM_SAVE(ARM_EWUPCT);
|
||||
ARM_SAVE(ARM_RSTCT1);
|
||||
ARM_SAVE(ARM_RSTCT2);
|
||||
ARM_SAVE(ARM_SYSST);
|
||||
ULPD_SAVE(ULPD_CLOCK_CTRL);
|
||||
ULPD_SAVE(ULPD_STATUS_REQ);
|
||||
|
||||
/*
|
||||
* Step 3: LOW_PWR signal enabling
|
||||
*
|
||||
* Allow the LOW_PWR signal to be visible on MPUIO5 ball.
|
||||
*/
|
||||
if (cpu_is_omap1510()) {
|
||||
/* POWER_CTRL_REG = 0x1 (LOW_POWER is available) */
|
||||
omap_writew(omap_readw(ULPD_POWER_CTRL) |
|
||||
OMAP1510_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL);
|
||||
} else if (cpu_is_omap16xx()) {
|
||||
/* POWER_CTRL_REG = 0x1 (LOW_POWER is available) */
|
||||
omap_writew(omap_readw(ULPD_POWER_CTRL) |
|
||||
OMAP1610_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL);
|
||||
}
|
||||
|
||||
/* configure LOW_PWR pin */
|
||||
omap_cfg_reg(T20_1610_LOW_PWR);
|
||||
|
||||
/*
|
||||
* Step 4: OMAP DSP Shutdown
|
||||
*/
|
||||
|
||||
/* Set DSP_RST = 1 and DSP_EN = 0, put DSP block into reset */
|
||||
omap_writel((omap_readl(ARM_RSTCT1) | DSP_RST) & ~DSP_ENABLE,
|
||||
ARM_RSTCT1);
|
||||
|
||||
/* Set DSP boot mode to DSP-IDLE, DSP_BOOT_MODE = 0x2 */
|
||||
omap_writel(DSP_IDLE_MODE, MPUI_DSP_BOOT_CONFIG);
|
||||
|
||||
/* Set EN_DSPCK = 0, stop DSP block clock */
|
||||
omap_writel(omap_readl(ARM_CKCTL) & ~DSP_CLOCK_ENABLE, ARM_CKCTL);
|
||||
|
||||
/* Stop any DSP domain clocks */
|
||||
omap_writel(omap_readl(ARM_IDLECT2) | (1<<EN_APICK), ARM_IDLECT2);
|
||||
save_dsp_idlect2 = __raw_readw(DSP_IDLECT2);
|
||||
__raw_writew(0, DSP_IDLECT2);
|
||||
|
||||
/*
|
||||
* Step 5: Wakeup Event Setup
|
||||
*/
|
||||
|
||||
omap_pm_wakeup_setup();
|
||||
|
||||
/*
|
||||
* Step 6a: ARM and Traffic controller shutdown
|
||||
*
|
||||
* Step 6 starts here with clock and watchdog disable
|
||||
*/
|
||||
|
||||
/* stop clocks */
|
||||
mask32 = omap_readl(ARM_IDLECT2);
|
||||
mask32 &= ~(1<<EN_WDTCK); /* bit 0 -> 0 (WDT clock) */
|
||||
mask32 |= (1<<EN_XORPCK); /* bit 1 -> 1 (XORPCK clock) */
|
||||
mask32 &= ~(1<<EN_PERCK); /* bit 2 -> 0 (MPUPER_CK clock) */
|
||||
mask32 &= ~(1<<EN_LCDCK); /* bit 3 -> 0 (LCDC clock) */
|
||||
mask32 &= ~(1<<EN_LBCK); /* bit 4 -> 0 (local bus clock) */
|
||||
mask32 |= (1<<EN_APICK); /* bit 6 -> 1 (MPUI clock) */
|
||||
mask32 &= ~(1<<EN_TIMCK); /* bit 7 -> 0 (MPU timer clock) */
|
||||
mask32 &= ~(1<<DMACK_REQ); /* bit 8 -> 0 (DMAC clock) */
|
||||
mask32 &= ~(1<<EN_GPIOCK); /* bit 9 -> 0 (GPIO clock) */
|
||||
omap_writel(mask32, ARM_IDLECT2);
|
||||
|
||||
/* disable ARM watchdog */
|
||||
omap_writel(0x00F5, OMAP_WDT_TIMER_MODE);
|
||||
omap_writel(0x00A0, OMAP_WDT_TIMER_MODE);
|
||||
|
||||
/*
|
||||
* Step 6b: ARM and Traffic controller shutdown
|
||||
*
|
||||
* Step 6 continues here. Prepare jump to power management
|
||||
* assembly code in internal SRAM.
|
||||
*
|
||||
* Since the omap_cpu_suspend routine has been copied to
|
||||
* SRAM, we'll do an indirect procedure call to it and pass the
|
||||
* contents of arm_idlect1 and arm_idlect2 so it can restore
|
||||
* them when it wakes up and it will return.
|
||||
*/
|
||||
|
||||
arg0 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT1];
|
||||
arg1 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT2];
|
||||
|
||||
if (cpu_is_omap1510()) {
|
||||
func_ptr = (void *)(OMAP1510_SRAM_API_SUSPEND);
|
||||
} else if (cpu_is_omap1610() || cpu_is_omap1710()) {
|
||||
func_ptr = (void *)(OMAP1610_SRAM_API_SUSPEND);
|
||||
} else if (cpu_is_omap5912()) {
|
||||
func_ptr = (void *)(OMAP5912_SRAM_API_SUSPEND);
|
||||
}
|
||||
|
||||
/*
|
||||
* Step 6c: ARM and Traffic controller shutdown
|
||||
*
|
||||
* Jump to assembly code. The processor will stay there
|
||||
* until wake up.
|
||||
*/
|
||||
|
||||
func_ptr(arg0, arg1);
|
||||
|
||||
/*
|
||||
* If we are here, processor is woken up!
|
||||
*/
|
||||
|
||||
if (cpu_is_omap1510()) {
|
||||
/* POWER_CTRL_REG = 0x0 (LOW_POWER is disabled) */
|
||||
omap_writew(omap_readw(ULPD_POWER_CTRL) &
|
||||
~OMAP1510_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL);
|
||||
} else if (cpu_is_omap16xx()) {
|
||||
/* POWER_CTRL_REG = 0x0 (LOW_POWER is disabled) */
|
||||
omap_writew(omap_readw(ULPD_POWER_CTRL) &
|
||||
~OMAP1610_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL);
|
||||
}
|
||||
|
||||
|
||||
/* Restore DSP clocks */
|
||||
omap_writel(omap_readl(ARM_IDLECT2) | (1<<EN_APICK), ARM_IDLECT2);
|
||||
__raw_writew(save_dsp_idlect2, DSP_IDLECT2);
|
||||
ARM_RESTORE(ARM_IDLECT2);
|
||||
|
||||
/*
|
||||
* Restore ARM state, except ARM_IDLECT1/2 which omap_cpu_suspend did
|
||||
*/
|
||||
|
||||
ARM_RESTORE(ARM_CKCTL);
|
||||
ARM_RESTORE(ARM_EWUPCT);
|
||||
ARM_RESTORE(ARM_RSTCT1);
|
||||
ARM_RESTORE(ARM_RSTCT2);
|
||||
ARM_RESTORE(ARM_SYSST);
|
||||
ULPD_RESTORE(ULPD_CLOCK_CTRL);
|
||||
ULPD_RESTORE(ULPD_STATUS_REQ);
|
||||
|
||||
if (cpu_is_omap1510()) {
|
||||
MPUI1510_RESTORE(MPUI_CTRL);
|
||||
MPUI1510_RESTORE(MPUI_DSP_BOOT_CONFIG);
|
||||
MPUI1510_RESTORE(MPUI_DSP_API_CONFIG);
|
||||
MPUI1510_RESTORE(EMIFS_CONFIG);
|
||||
MPUI1510_RESTORE(EMIFF_SDRAM_CONFIG);
|
||||
MPUI1510_RESTORE(OMAP_IH1_MIR);
|
||||
MPUI1510_RESTORE(OMAP_IH2_MIR);
|
||||
} else if (cpu_is_omap16xx()) {
|
||||
MPUI1610_RESTORE(MPUI_CTRL);
|
||||
MPUI1610_RESTORE(MPUI_DSP_BOOT_CONFIG);
|
||||
MPUI1610_RESTORE(MPUI_DSP_API_CONFIG);
|
||||
MPUI1610_RESTORE(EMIFS_CONFIG);
|
||||
MPUI1610_RESTORE(EMIFF_SDRAM_CONFIG);
|
||||
|
||||
MPUI1610_RESTORE(OMAP_IH1_MIR);
|
||||
MPUI1610_RESTORE(OMAP_IH2_0_MIR);
|
||||
MPUI1610_RESTORE(OMAP_IH2_1_MIR);
|
||||
MPUI1610_RESTORE(OMAP_IH2_2_MIR);
|
||||
MPUI1610_RESTORE(OMAP_IH2_3_MIR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reenable interrupts
|
||||
*/
|
||||
|
||||
local_irq_enable();
|
||||
local_fiq_enable();
|
||||
|
||||
printk("PM: OMAP%x is re-starting from deep sleep...\n", system_rev);
|
||||
|
||||
if (machine_is_omap_osk()) {
|
||||
/* Let LED1 (D9) blink again */
|
||||
tps65010_set_led(LED1, BLINK);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(DEBUG) && defined(CONFIG_PROC_FS)
|
||||
static int g_read_completed;
|
||||
|
||||
/*
|
||||
* Read system PM registers for debugging
|
||||
*/
|
||||
static int omap_pm_read_proc(
|
||||
char *page_buffer,
|
||||
char **my_first_byte,
|
||||
off_t virtual_start,
|
||||
int length,
|
||||
int *eof,
|
||||
void *data)
|
||||
{
|
||||
int my_buffer_offset = 0;
|
||||
char * const my_base = page_buffer;
|
||||
|
||||
ARM_SAVE(ARM_CKCTL);
|
||||
ARM_SAVE(ARM_IDLECT1);
|
||||
ARM_SAVE(ARM_IDLECT2);
|
||||
ARM_SAVE(ARM_EWUPCT);
|
||||
ARM_SAVE(ARM_RSTCT1);
|
||||
ARM_SAVE(ARM_RSTCT2);
|
||||
ARM_SAVE(ARM_SYSST);
|
||||
|
||||
ULPD_SAVE(ULPD_IT_STATUS);
|
||||
ULPD_SAVE(ULPD_CLOCK_CTRL);
|
||||
ULPD_SAVE(ULPD_SOFT_REQ);
|
||||
ULPD_SAVE(ULPD_STATUS_REQ);
|
||||
ULPD_SAVE(ULPD_DPLL_CTRL);
|
||||
ULPD_SAVE(ULPD_POWER_CTRL);
|
||||
|
||||
if (cpu_is_omap1510()) {
|
||||
MPUI1510_SAVE(MPUI_CTRL);
|
||||
MPUI1510_SAVE(MPUI_DSP_STATUS);
|
||||
MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG);
|
||||
MPUI1510_SAVE(MPUI_DSP_API_CONFIG);
|
||||
MPUI1510_SAVE(EMIFF_SDRAM_CONFIG);
|
||||
MPUI1510_SAVE(EMIFS_CONFIG);
|
||||
} else if (cpu_is_omap16xx()) {
|
||||
MPUI1610_SAVE(MPUI_CTRL);
|
||||
MPUI1610_SAVE(MPUI_DSP_STATUS);
|
||||
MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG);
|
||||
MPUI1610_SAVE(MPUI_DSP_API_CONFIG);
|
||||
MPUI1610_SAVE(EMIFF_SDRAM_CONFIG);
|
||||
MPUI1610_SAVE(EMIFS_CONFIG);
|
||||
}
|
||||
|
||||
if (virtual_start == 0) {
|
||||
g_read_completed = 0;
|
||||
|
||||
my_buffer_offset += sprintf(my_base + my_buffer_offset,
|
||||
"ARM_CKCTL_REG: 0x%-8x \n"
|
||||
"ARM_IDLECT1_REG: 0x%-8x \n"
|
||||
"ARM_IDLECT2_REG: 0x%-8x \n"
|
||||
"ARM_EWUPCT_REG: 0x%-8x \n"
|
||||
"ARM_RSTCT1_REG: 0x%-8x \n"
|
||||
"ARM_RSTCT2_REG: 0x%-8x \n"
|
||||
"ARM_SYSST_REG: 0x%-8x \n"
|
||||
"ULPD_IT_STATUS_REG: 0x%-4x \n"
|
||||
"ULPD_CLOCK_CTRL_REG: 0x%-4x \n"
|
||||
"ULPD_SOFT_REQ_REG: 0x%-4x \n"
|
||||
"ULPD_DPLL_CTRL_REG: 0x%-4x \n"
|
||||
"ULPD_STATUS_REQ_REG: 0x%-4x \n"
|
||||
"ULPD_POWER_CTRL_REG: 0x%-4x \n",
|
||||
ARM_SHOW(ARM_CKCTL),
|
||||
ARM_SHOW(ARM_IDLECT1),
|
||||
ARM_SHOW(ARM_IDLECT2),
|
||||
ARM_SHOW(ARM_EWUPCT),
|
||||
ARM_SHOW(ARM_RSTCT1),
|
||||
ARM_SHOW(ARM_RSTCT2),
|
||||
ARM_SHOW(ARM_SYSST),
|
||||
ULPD_SHOW(ULPD_IT_STATUS),
|
||||
ULPD_SHOW(ULPD_CLOCK_CTRL),
|
||||
ULPD_SHOW(ULPD_SOFT_REQ),
|
||||
ULPD_SHOW(ULPD_DPLL_CTRL),
|
||||
ULPD_SHOW(ULPD_STATUS_REQ),
|
||||
ULPD_SHOW(ULPD_POWER_CTRL));
|
||||
|
||||
if (cpu_is_omap1510()) {
|
||||
my_buffer_offset += sprintf(my_base + my_buffer_offset,
|
||||
"MPUI1510_CTRL_REG 0x%-8x \n"
|
||||
"MPUI1510_DSP_STATUS_REG: 0x%-8x \n"
|
||||
"MPUI1510_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
|
||||
"MPUI1510_DSP_API_CONFIG_REG: 0x%-8x \n"
|
||||
"MPUI1510_SDRAM_CONFIG_REG: 0x%-8x \n"
|
||||
"MPUI1510_EMIFS_CONFIG_REG: 0x%-8x \n",
|
||||
MPUI1510_SHOW(MPUI_CTRL),
|
||||
MPUI1510_SHOW(MPUI_DSP_STATUS),
|
||||
MPUI1510_SHOW(MPUI_DSP_BOOT_CONFIG),
|
||||
MPUI1510_SHOW(MPUI_DSP_API_CONFIG),
|
||||
MPUI1510_SHOW(EMIFF_SDRAM_CONFIG),
|
||||
MPUI1510_SHOW(EMIFS_CONFIG));
|
||||
} else if (cpu_is_omap16xx()) {
|
||||
my_buffer_offset += sprintf(my_base + my_buffer_offset,
|
||||
"MPUI1610_CTRL_REG 0x%-8x \n"
|
||||
"MPUI1610_DSP_STATUS_REG: 0x%-8x \n"
|
||||
"MPUI1610_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
|
||||
"MPUI1610_DSP_API_CONFIG_REG: 0x%-8x \n"
|
||||
"MPUI1610_SDRAM_CONFIG_REG: 0x%-8x \n"
|
||||
"MPUI1610_EMIFS_CONFIG_REG: 0x%-8x \n",
|
||||
MPUI1610_SHOW(MPUI_CTRL),
|
||||
MPUI1610_SHOW(MPUI_DSP_STATUS),
|
||||
MPUI1610_SHOW(MPUI_DSP_BOOT_CONFIG),
|
||||
MPUI1610_SHOW(MPUI_DSP_API_CONFIG),
|
||||
MPUI1610_SHOW(EMIFF_SDRAM_CONFIG),
|
||||
MPUI1610_SHOW(EMIFS_CONFIG));
|
||||
}
|
||||
|
||||
g_read_completed++;
|
||||
} else if (g_read_completed >= 1) {
|
||||
*eof = 1;
|
||||
return 0;
|
||||
}
|
||||
g_read_completed++;
|
||||
|
||||
*my_first_byte = page_buffer;
|
||||
return my_buffer_offset;
|
||||
}
|
||||
|
||||
static void omap_pm_init_proc(void)
|
||||
{
|
||||
struct proc_dir_entry *entry;
|
||||
|
||||
entry = create_proc_read_entry("driver/omap_pm",
|
||||
S_IWUSR | S_IRUGO, NULL,
|
||||
omap_pm_read_proc, 0);
|
||||
}
|
||||
|
||||
#endif /* DEBUG && CONFIG_PROC_FS */
|
||||
|
||||
/*
|
||||
* omap_pm_prepare - Do preliminary suspend work.
|
||||
* @state: suspend state we're entering.
|
||||
*
|
||||
*/
|
||||
//#include <asm/arch/hardware.h>
|
||||
|
||||
static int omap_pm_prepare(suspend_state_t state)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case PM_SUSPEND_STANDBY:
|
||||
case PM_SUSPEND_MEM:
|
||||
break;
|
||||
|
||||
case PM_SUSPEND_DISK:
|
||||
return -ENOTSUPP;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* omap_pm_enter - Actually enter a sleep state.
|
||||
* @state: State we're entering.
|
||||
*
|
||||
*/
|
||||
|
||||
static int omap_pm_enter(suspend_state_t state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case PM_SUSPEND_STANDBY:
|
||||
case PM_SUSPEND_MEM:
|
||||
omap_pm_suspend();
|
||||
break;
|
||||
|
||||
case PM_SUSPEND_DISK:
|
||||
return -ENOTSUPP;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* omap_pm_finish - Finish up suspend sequence.
|
||||
* @state: State we're coming out of.
|
||||
*
|
||||
* This is called after we wake back up (or if entering the sleep state
|
||||
* failed).
|
||||
*/
|
||||
|
||||
static int omap_pm_finish(suspend_state_t state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct pm_ops omap_pm_ops ={
|
||||
.pm_disk_mode = 0,
|
||||
.prepare = omap_pm_prepare,
|
||||
.enter = omap_pm_enter,
|
||||
.finish = omap_pm_finish,
|
||||
};
|
||||
|
||||
static int __init omap_pm_init(void)
|
||||
{
|
||||
printk("Power Management for TI OMAP.\n");
|
||||
pm_idle = omap_pm_idle;
|
||||
/*
|
||||
* We copy the assembler sleep/wakeup routines to SRAM.
|
||||
* These routines need to be in SRAM as that's the only
|
||||
* memory the MPU can see when it wakes up.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP1510
|
||||
if (cpu_is_omap1510()) {
|
||||
memcpy((void *)OMAP1510_SRAM_IDLE_SUSPEND,
|
||||
omap1510_idle_loop_suspend,
|
||||
omap1510_idle_loop_suspend_sz);
|
||||
memcpy((void *)OMAP1510_SRAM_API_SUSPEND, omap1510_cpu_suspend,
|
||||
omap1510_cpu_suspend_sz);
|
||||
} else
|
||||
#endif
|
||||
if (cpu_is_omap1610() || cpu_is_omap1710()) {
|
||||
memcpy((void *)OMAP1610_SRAM_IDLE_SUSPEND,
|
||||
omap1610_idle_loop_suspend,
|
||||
omap1610_idle_loop_suspend_sz);
|
||||
memcpy((void *)OMAP1610_SRAM_API_SUSPEND, omap1610_cpu_suspend,
|
||||
omap1610_cpu_suspend_sz);
|
||||
} else if (cpu_is_omap5912()) {
|
||||
memcpy((void *)OMAP5912_SRAM_IDLE_SUSPEND,
|
||||
omap1610_idle_loop_suspend,
|
||||
omap1610_idle_loop_suspend_sz);
|
||||
memcpy((void *)OMAP5912_SRAM_API_SUSPEND, omap1610_cpu_suspend,
|
||||
omap1610_cpu_suspend_sz);
|
||||
}
|
||||
|
||||
pm_set_ops(&omap_pm_ops);
|
||||
|
||||
#if defined(DEBUG) && defined(CONFIG_PROC_FS)
|
||||
omap_pm_init_proc();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
__initcall(omap_pm_init);
|
||||
|
@ -1,314 +0,0 @@
|
||||
/*
|
||||
* linux/arch/arm/mach-omap/sleep.S
|
||||
*
|
||||
* Low-level OMAP1510/1610 sleep/wakeUp support
|
||||
*
|
||||
* Initial SA1110 code:
|
||||
* Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
|
||||
*
|
||||
* Adapted for PXA by Nicolas Pitre:
|
||||
* Copyright (c) 2002 Monta Vista Software, Inc.
|
||||
*
|
||||
* Support for OMAP1510/1610 by Dirk Behme <dirk.behme@de.bosch.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/assembler.h>
|
||||
#include <asm/arch/io.h>
|
||||
#include <asm/arch/pm.h>
|
||||
|
||||
.text
|
||||
|
||||
/*
|
||||
* Forces OMAP into idle state
|
||||
*
|
||||
* omapXXXX_idle_loop_suspend()
|
||||
*
|
||||
* Note: This code get's copied to internal SRAM at boot. When the OMAP
|
||||
* wakes up it continues execution at the point it went to sleep.
|
||||
*
|
||||
* Note: Because of slightly different configuration values we have
|
||||
* processor specific functions here.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP1510
|
||||
ENTRY(omap1510_idle_loop_suspend)
|
||||
|
||||
stmfd sp!, {r0 - r12, lr} @ save registers on stack
|
||||
|
||||
@ load base address of ARM_IDLECT1 and ARM_IDLECT2
|
||||
mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000
|
||||
orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
|
||||
orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
|
||||
|
||||
@ turn off clock domains
|
||||
@ get ARM_IDLECT2 into r2
|
||||
ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
|
||||
mov r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff
|
||||
orr r5,r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00
|
||||
strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
|
||||
|
||||
@ request ARM idle
|
||||
@ get ARM_IDLECT1 into r1
|
||||
ldrh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
|
||||
orr r3, r1, #OMAP1510_IDLE_LOOP_REQUEST & 0xffff
|
||||
strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
|
||||
|
||||
mov r5, #IDLE_WAIT_CYCLES & 0xff
|
||||
orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00
|
||||
l_1510: subs r5, r5, #1
|
||||
bne l_1510
|
||||
/*
|
||||
* Let's wait for the next clock tick to wake us up.
|
||||
*/
|
||||
mov r0, #0
|
||||
mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt
|
||||
/*
|
||||
* omap1510_idle_loop_suspend()'s resume point.
|
||||
*
|
||||
* It will just start executing here, so we'll restore stuff from the
|
||||
* stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
|
||||
*/
|
||||
|
||||
@ restore ARM_IDLECT1 and ARM_IDLECT2 and return
|
||||
@ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2
|
||||
strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
|
||||
strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
|
||||
|
||||
ldmfd sp!, {r0 - r12, pc} @ restore regs and return
|
||||
|
||||
ENTRY(omap1510_idle_loop_suspend_sz)
|
||||
.word . - omap1510_idle_loop_suspend
|
||||
#endif /* CONFIG_ARCH_OMAP1510 */
|
||||
|
||||
#if defined(CONFIG_ARCH_OMAP16XX)
|
||||
ENTRY(omap1610_idle_loop_suspend)
|
||||
|
||||
stmfd sp!, {r0 - r12, lr} @ save registers on stack
|
||||
|
||||
@ load base address of ARM_IDLECT1 and ARM_IDLECT2
|
||||
mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000
|
||||
orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
|
||||
orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
|
||||
|
||||
@ turn off clock domains
|
||||
@ get ARM_IDLECT2 into r2
|
||||
ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
|
||||
mov r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff
|
||||
orr r5,r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff00
|
||||
strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
|
||||
|
||||
@ request ARM idle
|
||||
@ get ARM_IDLECT1 into r1
|
||||
ldrh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
|
||||
orr r3, r1, #OMAP1610_IDLE_LOOP_REQUEST & 0xffff
|
||||
strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
|
||||
|
||||
mov r5, #IDLE_WAIT_CYCLES & 0xff
|
||||
orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00
|
||||
l_1610: subs r5, r5, #1
|
||||
bne l_1610
|
||||
/*
|
||||
* Let's wait for the next clock tick to wake us up.
|
||||
*/
|
||||
mov r0, #0
|
||||
mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt
|
||||
/*
|
||||
* omap1610_idle_loop_suspend()'s resume point.
|
||||
*
|
||||
* It will just start executing here, so we'll restore stuff from the
|
||||
* stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
|
||||
*/
|
||||
|
||||
@ restore ARM_IDLECT1 and ARM_IDLECT2 and return
|
||||
@ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2
|
||||
strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
|
||||
strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
|
||||
|
||||
ldmfd sp!, {r0 - r12, pc} @ restore regs and return
|
||||
|
||||
ENTRY(omap1610_idle_loop_suspend_sz)
|
||||
.word . - omap1610_idle_loop_suspend
|
||||
#endif /* CONFIG_ARCH_OMAP16XX */
|
||||
|
||||
/*
|
||||
* Forces OMAP into deep sleep state
|
||||
*
|
||||
* omapXXXX_cpu_suspend()
|
||||
*
|
||||
* The values of the registers ARM_IDLECT1 and ARM_IDLECT2 are passed
|
||||
* as arg0 and arg1 from caller. arg0 is stored in register r0 and arg1
|
||||
* in register r1.
|
||||
*
|
||||
* Note: This code get's copied to internal SRAM at boot. When the OMAP
|
||||
* wakes up it continues execution at the point it went to sleep.
|
||||
*
|
||||
* Note: Because of errata work arounds we have processor specific functions
|
||||
* here. They are mostly the same, but slightly different.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP1510
|
||||
ENTRY(omap1510_cpu_suspend)
|
||||
|
||||
@ save registers on stack
|
||||
stmfd sp!, {r0 - r12, lr}
|
||||
|
||||
@ load base address of Traffic Controller
|
||||
mov r4, #TCMIF_ASM_BASE & 0xff000000
|
||||
orr r4, r4, #TCMIF_ASM_BASE & 0x00ff0000
|
||||
orr r4, r4, #TCMIF_ASM_BASE & 0x0000ff00
|
||||
|
||||
@ work around errata of OMAP1510 PDE bit for TC shut down
|
||||
@ clear PDE bit
|
||||
ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
|
||||
bic r5, r5, #PDE_BIT & 0xff
|
||||
str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
|
||||
|
||||
@ set PWD_EN bit
|
||||
and r5, r5, #PWD_EN_BIT & 0xff
|
||||
str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
|
||||
|
||||
@ prepare to put SDRAM into self-refresh manually
|
||||
ldr r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
|
||||
orr r5, r5, #SELF_REFRESH_MODE & 0xff000000
|
||||
orr r5, r5, #SELF_REFRESH_MODE & 0x000000ff
|
||||
str r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
|
||||
|
||||
@ prepare to put EMIFS to Sleep
|
||||
ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
|
||||
orr r5, r5, #IDLE_EMIFS_REQUEST & 0xff
|
||||
str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
|
||||
|
||||
@ load base address of ARM_IDLECT1 and ARM_IDLECT2
|
||||
mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000
|
||||
orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
|
||||
orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
|
||||
|
||||
@ turn off clock domains
|
||||
mov r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff
|
||||
orr r5,r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00
|
||||
strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
|
||||
|
||||
@ request ARM idle
|
||||
mov r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff
|
||||
orr r3, r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff00
|
||||
strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
|
||||
|
||||
mov r5, #IDLE_WAIT_CYCLES & 0xff
|
||||
orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00
|
||||
l_1510_2:
|
||||
subs r5, r5, #1
|
||||
bne l_1510_2
|
||||
/*
|
||||
* Let's wait for the next wake up event to wake us up. r0 can't be
|
||||
* used here because r0 holds ARM_IDLECT1
|
||||
*/
|
||||
mov r2, #0
|
||||
mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt
|
||||
/*
|
||||
* omap1510_cpu_suspend()'s resume point.
|
||||
*
|
||||
* It will just start executing here, so we'll restore stuff from the
|
||||
* stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
|
||||
*/
|
||||
strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
|
||||
strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
|
||||
|
||||
@ restore regs and return
|
||||
ldmfd sp!, {r0 - r12, pc}
|
||||
|
||||
ENTRY(omap1510_cpu_suspend_sz)
|
||||
.word . - omap1510_cpu_suspend
|
||||
#endif /* CONFIG_ARCH_OMAP1510 */
|
||||
|
||||
#if defined(CONFIG_ARCH_OMAP16XX)
|
||||
ENTRY(omap1610_cpu_suspend)
|
||||
|
||||
@ save registers on stack
|
||||
stmfd sp!, {r0 - r12, lr}
|
||||
|
||||
@ load base address of Traffic Controller
|
||||
mov r4, #TCMIF_ASM_BASE & 0xff000000
|
||||
orr r4, r4, #TCMIF_ASM_BASE & 0x00ff0000
|
||||
orr r4, r4, #TCMIF_ASM_BASE & 0x0000ff00
|
||||
|
||||
@ prepare to put SDRAM into self-refresh manually
|
||||
ldr r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
|
||||
orr r5, r5, #SELF_REFRESH_MODE & 0xff000000
|
||||
orr r5, r5, #SELF_REFRESH_MODE & 0x000000ff
|
||||
str r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
|
||||
|
||||
@ prepare to put EMIFS to Sleep
|
||||
ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
|
||||
orr r5, r5, #IDLE_EMIFS_REQUEST & 0xff
|
||||
str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
|
||||
|
||||
@ load base address of ARM_IDLECT1 and ARM_IDLECT2
|
||||
mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000
|
||||
orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
|
||||
orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
|
||||
|
||||
@ turn off clock domains
|
||||
mov r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff
|
||||
orr r5,r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff00
|
||||
strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
|
||||
|
||||
@ work around errata of OMAP1610/5912. Enable (!) peripheral
|
||||
@ clock to let the chip go into deep sleep
|
||||
ldrh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
|
||||
orr r5,r5, #EN_PERCK_BIT & 0xff
|
||||
strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
|
||||
|
||||
@ request ARM idle
|
||||
mov r3, #OMAP1610_DEEP_SLEEP_REQUEST & 0xff
|
||||
orr r3, r3, #OMAP1610_DEEP_SLEEP_REQUEST & 0xff00
|
||||
strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
|
||||
|
||||
mov r5, #IDLE_WAIT_CYCLES & 0xff
|
||||
orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00
|
||||
l_1610_2:
|
||||
subs r5, r5, #1
|
||||
bne l_1610_2
|
||||
/*
|
||||
* Let's wait for the next wake up event to wake us up. r0 can't be
|
||||
* used here because r0 holds ARM_IDLECT1
|
||||
*/
|
||||
mov r2, #0
|
||||
mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt
|
||||
/*
|
||||
* omap1610_cpu_suspend()'s resume point.
|
||||
*
|
||||
* It will just start executing here, so we'll restore stuff from the
|
||||
* stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
|
||||
*/
|
||||
strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
|
||||
strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
|
||||
|
||||
@ restore regs and return
|
||||
ldmfd sp!, {r0 - r12, pc}
|
||||
|
||||
ENTRY(omap1610_cpu_suspend_sz)
|
||||
.word . - omap1610_cpu_suspend
|
||||
#endif /* CONFIG_ARCH_OMAP16XX */
|
@ -1,593 +0,0 @@
|
||||
/*
|
||||
* arch/arm/mach-omap/usb.c -- platform level USB initialization
|
||||
*
|
||||
* Copyright (C) 2004 Texas Instruments, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/usb_otg.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/hardware.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
#include <asm/arch/mux.h>
|
||||
#include <asm/arch/usb.h>
|
||||
#include <asm/arch/board.h>
|
||||
|
||||
/* These routines should handle the standard chip-specific modes
|
||||
* for usb0/1/2 ports, covering basic mux and transceiver setup.
|
||||
*
|
||||
* Some board-*.c files will need to set up additional mux options,
|
||||
* like for suspend handling, vbus sensing, GPIOs, and the D+ pullup.
|
||||
*/
|
||||
|
||||
/* TESTED ON:
|
||||
* - 1611B H2 (with usb1 mini-AB) using standard Mini-B or OTG cables
|
||||
* - 5912 OSK OHCI (with usb0 standard-A), standard A-to-B cables
|
||||
* - 5912 OSK UDC, with *nonstandard* A-to-A cable
|
||||
* - 1510 Innovator UDC with bundled usb0 cable
|
||||
* - 1510 Innovator OHCI with bundled usb1/usb2 cable
|
||||
* - 1510 Innovator OHCI with custom usb0 cable, feeding 5V VBUS
|
||||
* - 1710 custom development board using alternate pin group
|
||||
* - 1710 H3 (with usb1 mini-AB) using standard Mini-B or OTG cables
|
||||
*/
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP_OTG
|
||||
|
||||
static struct otg_transceiver *xceiv;
|
||||
|
||||
/**
|
||||
* otg_get_transceiver - find the (single) OTG transceiver driver
|
||||
*
|
||||
* Returns the transceiver driver, after getting a refcount to it; or
|
||||
* null if there is no such transceiver. The caller is responsible for
|
||||
* releasing that count.
|
||||
*/
|
||||
struct otg_transceiver *otg_get_transceiver(void)
|
||||
{
|
||||
if (xceiv)
|
||||
get_device(xceiv->dev);
|
||||
return xceiv;
|
||||
}
|
||||
EXPORT_SYMBOL(otg_get_transceiver);
|
||||
|
||||
int otg_set_transceiver(struct otg_transceiver *x)
|
||||
{
|
||||
if (xceiv && x)
|
||||
return -EBUSY;
|
||||
xceiv = x;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(otg_set_transceiver);
|
||||
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static u32 __init omap_usb0_init(unsigned nwires, unsigned is_device)
|
||||
{
|
||||
u32 syscon1 = 0;
|
||||
|
||||
if (nwires == 0) {
|
||||
if (!cpu_is_omap15xx()) {
|
||||
/* pulldown D+/D- */
|
||||
USB_TRANSCEIVER_CTRL_REG &= ~(3 << 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_device)
|
||||
omap_cfg_reg(W4_USB_PUEN);
|
||||
|
||||
/* internal transceiver */
|
||||
if (nwires == 2) {
|
||||
// omap_cfg_reg(P9_USB_DP);
|
||||
// omap_cfg_reg(R8_USB_DM);
|
||||
|
||||
if (cpu_is_omap15xx()) {
|
||||
/* This works on 1510-Innovator */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* NOTES:
|
||||
* - peripheral should configure VBUS detection!
|
||||
* - only peripherals may use the internal D+/D- pulldowns
|
||||
* - OTG support on this port not yet written
|
||||
*/
|
||||
|
||||
USB_TRANSCEIVER_CTRL_REG &= ~(7 << 4);
|
||||
if (!is_device)
|
||||
USB_TRANSCEIVER_CTRL_REG |= (3 << 1);
|
||||
|
||||
return 3 << 16;
|
||||
}
|
||||
|
||||
/* alternate pin config, external transceiver */
|
||||
if (cpu_is_omap15xx()) {
|
||||
printk(KERN_ERR "no usb0 alt pin config on 15xx\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
omap_cfg_reg(V6_USB0_TXD);
|
||||
omap_cfg_reg(W9_USB0_TXEN);
|
||||
omap_cfg_reg(W5_USB0_SE0);
|
||||
|
||||
/* NOTE: SPEED and SUSP aren't configured here */
|
||||
|
||||
if (nwires != 3)
|
||||
omap_cfg_reg(Y5_USB0_RCV);
|
||||
if (nwires != 6)
|
||||
USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB2_UNI_R;
|
||||
|
||||
switch (nwires) {
|
||||
case 3:
|
||||
syscon1 = 2;
|
||||
break;
|
||||
case 4:
|
||||
syscon1 = 1;
|
||||
break;
|
||||
case 6:
|
||||
syscon1 = 3;
|
||||
omap_cfg_reg(AA9_USB0_VP);
|
||||
omap_cfg_reg(R9_USB0_VM);
|
||||
USB_TRANSCEIVER_CTRL_REG |= CONF_USB2_UNI_R;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
|
||||
0, nwires);
|
||||
}
|
||||
return syscon1 << 16;
|
||||
}
|
||||
|
||||
static u32 __init omap_usb1_init(unsigned nwires)
|
||||
{
|
||||
u32 syscon1 = 0;
|
||||
|
||||
if (nwires != 6 && !cpu_is_omap15xx())
|
||||
USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB1_UNI_R;
|
||||
if (nwires == 0)
|
||||
return 0;
|
||||
|
||||
/* external transceiver */
|
||||
omap_cfg_reg(USB1_TXD);
|
||||
omap_cfg_reg(USB1_TXEN);
|
||||
if (cpu_is_omap15xx()) {
|
||||
omap_cfg_reg(USB1_SEO);
|
||||
omap_cfg_reg(USB1_SPEED);
|
||||
// SUSP
|
||||
} else if (cpu_is_omap1610() || cpu_is_omap5912()) {
|
||||
omap_cfg_reg(W13_1610_USB1_SE0);
|
||||
omap_cfg_reg(R13_1610_USB1_SPEED);
|
||||
// SUSP
|
||||
} else if (cpu_is_omap1710()) {
|
||||
omap_cfg_reg(R13_1710_USB1_SE0);
|
||||
// SUSP
|
||||
} else {
|
||||
pr_debug("usb unrecognized\n");
|
||||
}
|
||||
if (nwires != 3)
|
||||
omap_cfg_reg(USB1_RCV);
|
||||
|
||||
switch (nwires) {
|
||||
case 3:
|
||||
syscon1 = 2;
|
||||
break;
|
||||
case 4:
|
||||
syscon1 = 1;
|
||||
break;
|
||||
case 6:
|
||||
syscon1 = 3;
|
||||
omap_cfg_reg(USB1_VP);
|
||||
omap_cfg_reg(USB1_VM);
|
||||
if (!cpu_is_omap15xx())
|
||||
USB_TRANSCEIVER_CTRL_REG |= CONF_USB1_UNI_R;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
|
||||
1, nwires);
|
||||
}
|
||||
return syscon1 << 20;
|
||||
}
|
||||
|
||||
static u32 __init omap_usb2_init(unsigned nwires, unsigned alt_pingroup)
|
||||
{
|
||||
u32 syscon1 = 0;
|
||||
|
||||
/* NOTE erratum: must leave USB2_UNI_R set if usb0 in use */
|
||||
if (alt_pingroup || nwires == 0)
|
||||
return 0;
|
||||
if (nwires != 6 && !cpu_is_omap15xx())
|
||||
USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB2_UNI_R;
|
||||
|
||||
/* external transceiver */
|
||||
if (cpu_is_omap15xx()) {
|
||||
omap_cfg_reg(USB2_TXD);
|
||||
omap_cfg_reg(USB2_TXEN);
|
||||
omap_cfg_reg(USB2_SEO);
|
||||
if (nwires != 3)
|
||||
omap_cfg_reg(USB2_RCV);
|
||||
/* there is no USB2_SPEED */
|
||||
} else if (cpu_is_omap16xx()) {
|
||||
omap_cfg_reg(V6_USB2_TXD);
|
||||
omap_cfg_reg(W9_USB2_TXEN);
|
||||
omap_cfg_reg(W5_USB2_SE0);
|
||||
if (nwires != 3)
|
||||
omap_cfg_reg(Y5_USB2_RCV);
|
||||
// FIXME omap_cfg_reg(USB2_SPEED);
|
||||
} else {
|
||||
pr_debug("usb unrecognized\n");
|
||||
}
|
||||
// omap_cfg_reg(USB2_SUSP);
|
||||
|
||||
switch (nwires) {
|
||||
case 3:
|
||||
syscon1 = 2;
|
||||
break;
|
||||
case 4:
|
||||
syscon1 = 1;
|
||||
break;
|
||||
case 6:
|
||||
syscon1 = 3;
|
||||
if (cpu_is_omap15xx()) {
|
||||
omap_cfg_reg(USB2_VP);
|
||||
omap_cfg_reg(USB2_VM);
|
||||
} else {
|
||||
omap_cfg_reg(AA9_USB2_VP);
|
||||
omap_cfg_reg(R9_USB2_VM);
|
||||
USB_TRANSCEIVER_CTRL_REG |= CONF_USB2_UNI_R;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
|
||||
2, nwires);
|
||||
}
|
||||
return syscon1 << 24;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#if defined(CONFIG_USB_GADGET_OMAP) || \
|
||||
defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) || \
|
||||
(defined(CONFIG_USB_OTG) && defined(CONFIG_ARCH_OMAP_OTG))
|
||||
static void usb_release(struct device *dev)
|
||||
{
|
||||
/* normally not freed */
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_OMAP
|
||||
|
||||
static struct resource udc_resources[] = {
|
||||
/* order is significant! */
|
||||
{ /* registers */
|
||||
.start = UDC_BASE,
|
||||
.end = UDC_BASE + 0xff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
}, { /* general IRQ */
|
||||
.start = IH2_BASE + 20,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
}, { /* PIO IRQ */
|
||||
.start = IH2_BASE + 30,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
}, { /* SOF IRQ */
|
||||
.start = IH2_BASE + 29,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static u64 udc_dmamask = ~(u32)0;
|
||||
|
||||
static struct platform_device udc_device = {
|
||||
.name = "omap_udc",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.release = usb_release,
|
||||
.dma_mask = &udc_dmamask,
|
||||
.coherent_dma_mask = 0xffffffff,
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(udc_resources),
|
||||
.resource = udc_resources,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
|
||||
|
||||
/* The dmamask must be set for OHCI to work */
|
||||
static u64 ohci_dmamask = ~(u32)0;
|
||||
|
||||
static struct resource ohci_resources[] = {
|
||||
{
|
||||
.start = OMAP_OHCI_BASE,
|
||||
.end = OMAP_OHCI_BASE + 4096,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
{
|
||||
.start = INT_USB_HHC_1,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device ohci_device = {
|
||||
.name = "ohci",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.release = usb_release,
|
||||
.dma_mask = &ohci_dmamask,
|
||||
.coherent_dma_mask = 0xffffffff,
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(ohci_resources),
|
||||
.resource = ohci_resources,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_OTG) && defined(CONFIG_ARCH_OMAP_OTG)
|
||||
|
||||
static struct resource otg_resources[] = {
|
||||
/* order is significant! */
|
||||
{
|
||||
.start = OTG_BASE,
|
||||
.end = OTG_BASE + 0xff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
}, {
|
||||
.start = IH2_BASE + 8,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device otg_device = {
|
||||
.name = "omap_otg",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.release = usb_release,
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(otg_resources),
|
||||
.resource = otg_resources,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#define ULPD_CLOCK_CTRL_REG __REG16(ULPD_CLOCK_CTRL)
|
||||
#define ULPD_SOFT_REQ_REG __REG16(ULPD_SOFT_REQ)
|
||||
|
||||
|
||||
// FIXME correct answer depends on hmc_mode,
|
||||
// as does any nonzero value for config->otg port number
|
||||
#ifdef CONFIG_USB_GADGET_OMAP
|
||||
#define is_usb0_device(config) 1
|
||||
#else
|
||||
#define is_usb0_device(config) 0
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP_OTG
|
||||
|
||||
void __init
|
||||
omap_otg_init(struct omap_usb_config *config)
|
||||
{
|
||||
u32 syscon = OTG_SYSCON_1_REG & 0xffff;
|
||||
int status;
|
||||
int alt_pingroup = 0;
|
||||
|
||||
/* NOTE: no bus or clock setup (yet?) */
|
||||
|
||||
syscon = OTG_SYSCON_1_REG & 0xffff;
|
||||
if (!(syscon & OTG_RESET_DONE))
|
||||
pr_debug("USB resets not complete?\n");
|
||||
|
||||
// OTG_IRQ_EN_REG = 0;
|
||||
|
||||
/* pin muxing and transceiver pinouts */
|
||||
if (config->pins[0] > 2) /* alt pingroup 2 */
|
||||
alt_pingroup = 1;
|
||||
syscon |= omap_usb0_init(config->pins[0], is_usb0_device(config));
|
||||
syscon |= omap_usb1_init(config->pins[1]);
|
||||
syscon |= omap_usb2_init(config->pins[2], alt_pingroup);
|
||||
pr_debug("OTG_SYSCON_1_REG = %08x\n", syscon);
|
||||
OTG_SYSCON_1_REG = syscon;
|
||||
|
||||
syscon = config->hmc_mode;
|
||||
syscon |= USBX_SYNCHRO | (4 << 16) /* B_ASE0_BRST */;
|
||||
#ifdef CONFIG_USB_OTG
|
||||
if (config->otg)
|
||||
syscon |= OTG_EN;
|
||||
#endif
|
||||
pr_debug("USB_TRANSCEIVER_CTRL_REG = %03x\n", USB_TRANSCEIVER_CTRL_REG);
|
||||
pr_debug("OTG_SYSCON_2_REG = %08x\n", syscon);
|
||||
OTG_SYSCON_2_REG = syscon;
|
||||
|
||||
printk("USB: hmc %d", config->hmc_mode);
|
||||
if (alt_pingroup)
|
||||
printk(", usb2 alt %d wires", config->pins[2]);
|
||||
else if (config->pins[0])
|
||||
printk(", usb0 %d wires%s", config->pins[0],
|
||||
is_usb0_device(config) ? " (dev)" : "");
|
||||
if (config->pins[1])
|
||||
printk(", usb1 %d wires", config->pins[1]);
|
||||
if (!alt_pingroup && config->pins[2])
|
||||
printk(", usb2 %d wires", config->pins[2]);
|
||||
if (config->otg)
|
||||
printk(", Mini-AB on usb%d", config->otg - 1);
|
||||
printk("\n");
|
||||
|
||||
/* leave USB clocks/controllers off until needed */
|
||||
ULPD_SOFT_REQ_REG &= ~SOFT_USB_CLK_REQ;
|
||||
ULPD_CLOCK_CTRL_REG &= ~USB_MCLK_EN;
|
||||
ULPD_CLOCK_CTRL_REG |= DIS_USB_PVCI_CLK;
|
||||
syscon = OTG_SYSCON_1_REG;
|
||||
syscon |= HST_IDLE_EN|DEV_IDLE_EN|OTG_IDLE_EN;
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_OMAP
|
||||
if (config->otg || config->register_dev) {
|
||||
syscon &= ~DEV_IDLE_EN;
|
||||
udc_device.dev.platform_data = config;
|
||||
/* FIXME patch IRQ numbers for omap730 */
|
||||
status = platform_device_register(&udc_device);
|
||||
if (status)
|
||||
pr_debug("can't register UDC device, %d\n", status);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
|
||||
if (config->otg || config->register_host) {
|
||||
syscon &= ~HST_IDLE_EN;
|
||||
ohci_device.dev.platform_data = config;
|
||||
if (cpu_is_omap730())
|
||||
ohci_resources[1].start = INT_730_USB_HHC_1;
|
||||
status = platform_device_register(&ohci_device);
|
||||
if (status)
|
||||
pr_debug("can't register OHCI device, %d\n", status);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_OTG
|
||||
if (config->otg) {
|
||||
syscon &= ~OTG_IDLE_EN;
|
||||
otg_device.dev.platform_data = config;
|
||||
if (cpu_is_omap730())
|
||||
otg_resources[1].start = INT_730_USB_OTG;
|
||||
status = platform_device_register(&otg_device);
|
||||
if (status)
|
||||
pr_debug("can't register OTG device, %d\n", status);
|
||||
}
|
||||
#endif
|
||||
pr_debug("OTG_SYSCON_1_REG = %08x\n", syscon);
|
||||
OTG_SYSCON_1_REG = syscon;
|
||||
|
||||
status = 0;
|
||||
}
|
||||
|
||||
#else
|
||||
static inline void omap_otg_init(struct omap_usb_config *config) {}
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP1510
|
||||
|
||||
#define ULPD_DPLL_CTRL_REG __REG16(ULPD_DPLL_CTRL)
|
||||
#define DPLL_IOB (1 << 13)
|
||||
#define DPLL_PLL_ENABLE (1 << 4)
|
||||
#define DPLL_LOCK (1 << 0)
|
||||
|
||||
#define ULPD_APLL_CTRL_REG __REG16(ULPD_APLL_CTRL)
|
||||
#define APLL_NDPLL_SWITCH (1 << 0)
|
||||
|
||||
|
||||
static void __init omap_1510_usb_init(struct omap_usb_config *config)
|
||||
{
|
||||
int status;
|
||||
unsigned int val;
|
||||
|
||||
omap_usb0_init(config->pins[0], is_usb0_device(config));
|
||||
omap_usb1_init(config->pins[1]);
|
||||
omap_usb2_init(config->pins[2], 0);
|
||||
|
||||
val = omap_readl(MOD_CONF_CTRL_0) & ~(0x3f << 1);
|
||||
val |= (config->hmc_mode << 1);
|
||||
omap_writel(val, MOD_CONF_CTRL_0);
|
||||
|
||||
printk("USB: hmc %d", config->hmc_mode);
|
||||
if (config->pins[0])
|
||||
printk(", usb0 %d wires%s", config->pins[0],
|
||||
is_usb0_device(config) ? " (dev)" : "");
|
||||
if (config->pins[1])
|
||||
printk(", usb1 %d wires", config->pins[1]);
|
||||
if (config->pins[2])
|
||||
printk(", usb2 %d wires", config->pins[2]);
|
||||
printk("\n");
|
||||
|
||||
/* use DPLL for 48 MHz function clock */
|
||||
pr_debug("APLL %04x DPLL %04x REQ %04x\n", ULPD_APLL_CTRL_REG,
|
||||
ULPD_DPLL_CTRL_REG, ULPD_SOFT_REQ_REG);
|
||||
ULPD_APLL_CTRL_REG &= ~APLL_NDPLL_SWITCH;
|
||||
ULPD_DPLL_CTRL_REG |= DPLL_IOB | DPLL_PLL_ENABLE;
|
||||
ULPD_SOFT_REQ_REG |= SOFT_UDC_REQ | SOFT_DPLL_REQ;
|
||||
while (!(ULPD_DPLL_CTRL_REG & DPLL_LOCK))
|
||||
cpu_relax();
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_OMAP
|
||||
if (config->register_dev) {
|
||||
udc_device.dev.platform_data = config;
|
||||
status = platform_device_register(&udc_device);
|
||||
if (status)
|
||||
pr_debug("can't register UDC device, %d\n", status);
|
||||
/* udc driver gates 48MHz by D+ pullup */
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
|
||||
if (config->register_host) {
|
||||
ohci_device.dev.platform_data = config;
|
||||
status = platform_device_register(&ohci_device);
|
||||
if (status)
|
||||
pr_debug("can't register OHCI device, %d\n", status);
|
||||
/* hcd explicitly gates 48MHz */
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#else
|
||||
static inline void omap_1510_usb_init(struct omap_usb_config *config) {}
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static struct omap_usb_config platform_data;
|
||||
|
||||
static int __init
|
||||
omap_usb_init(void)
|
||||
{
|
||||
const struct omap_usb_config *config;
|
||||
|
||||
config = omap_get_config(OMAP_TAG_USB, struct omap_usb_config);
|
||||
if (config == NULL) {
|
||||
printk(KERN_ERR "USB: No board-specific "
|
||||
"platform config found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
platform_data = *config;
|
||||
|
||||
if (cpu_is_omap730() || cpu_is_omap16xx())
|
||||
omap_otg_init(&platform_data);
|
||||
else if (cpu_is_omap15xx())
|
||||
omap_1510_usb_init(&platform_data);
|
||||
else {
|
||||
printk(KERN_ERR "USB: No init for your chip yet\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
subsys_initcall(omap_usb_init);
|
Loading…
Reference in New Issue
Block a user