mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-08 09:08:05 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
6
arch/mips/alchemy/devboards/Makefile
Normal file
6
arch/mips/alchemy/devboards/Makefile
Normal file
|
@ -0,0 +1,6 @@
|
|||
#
|
||||
# Alchemy Develboards
|
||||
#
|
||||
|
||||
obj-y += bcsr.o platform.o db1000.o db1200.o db1300.o db1550.o db1xxx.o
|
||||
obj-$(CONFIG_PM) += pm.o
|
143
arch/mips/alchemy/devboards/bcsr.c
Normal file
143
arch/mips/alchemy/devboards/bcsr.c
Normal file
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* bcsr.h -- Db1xxx/Pb1xxx Devboard CPLD registers ("BCSR") abstraction.
|
||||
*
|
||||
* All Alchemy development boards (except, of course, the weird PB1000)
|
||||
* have a few registers in a CPLD with standardised layout; they mostly
|
||||
* only differ in base address.
|
||||
* All registers are 16bits wide with 32bit spacing.
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/irq.h>
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/mach-db1x00/bcsr.h>
|
||||
|
||||
static struct bcsr_reg {
|
||||
void __iomem *raddr;
|
||||
spinlock_t lock;
|
||||
} bcsr_regs[BCSR_CNT];
|
||||
|
||||
static void __iomem *bcsr_virt; /* KSEG1 addr of BCSR base */
|
||||
static int bcsr_csc_base; /* linux-irq of first cascaded irq */
|
||||
|
||||
void __init bcsr_init(unsigned long bcsr1_phys, unsigned long bcsr2_phys)
|
||||
{
|
||||
int i;
|
||||
|
||||
bcsr1_phys = KSEG1ADDR(CPHYSADDR(bcsr1_phys));
|
||||
bcsr2_phys = KSEG1ADDR(CPHYSADDR(bcsr2_phys));
|
||||
|
||||
bcsr_virt = (void __iomem *)bcsr1_phys;
|
||||
|
||||
for (i = 0; i < BCSR_CNT; i++) {
|
||||
if (i >= BCSR_HEXLEDS)
|
||||
bcsr_regs[i].raddr = (void __iomem *)bcsr2_phys +
|
||||
(0x04 * (i - BCSR_HEXLEDS));
|
||||
else
|
||||
bcsr_regs[i].raddr = (void __iomem *)bcsr1_phys +
|
||||
(0x04 * i);
|
||||
|
||||
spin_lock_init(&bcsr_regs[i].lock);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned short bcsr_read(enum bcsr_id reg)
|
||||
{
|
||||
unsigned short r;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&bcsr_regs[reg].lock, flags);
|
||||
r = __raw_readw(bcsr_regs[reg].raddr);
|
||||
spin_unlock_irqrestore(&bcsr_regs[reg].lock, flags);
|
||||
return r;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcsr_read);
|
||||
|
||||
void bcsr_write(enum bcsr_id reg, unsigned short val)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&bcsr_regs[reg].lock, flags);
|
||||
__raw_writew(val, bcsr_regs[reg].raddr);
|
||||
wmb();
|
||||
spin_unlock_irqrestore(&bcsr_regs[reg].lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcsr_write);
|
||||
|
||||
void bcsr_mod(enum bcsr_id reg, unsigned short clr, unsigned short set)
|
||||
{
|
||||
unsigned short r;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&bcsr_regs[reg].lock, flags);
|
||||
r = __raw_readw(bcsr_regs[reg].raddr);
|
||||
r &= ~clr;
|
||||
r |= set;
|
||||
__raw_writew(r, bcsr_regs[reg].raddr);
|
||||
wmb();
|
||||
spin_unlock_irqrestore(&bcsr_regs[reg].lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcsr_mod);
|
||||
|
||||
/*
|
||||
* DB1200/PB1200 CPLD IRQ muxer
|
||||
*/
|
||||
static void bcsr_csc_handler(unsigned int irq, struct irq_desc *d)
|
||||
{
|
||||
unsigned short bisr = __raw_readw(bcsr_virt + BCSR_REG_INTSTAT);
|
||||
|
||||
disable_irq_nosync(irq);
|
||||
generic_handle_irq(bcsr_csc_base + __ffs(bisr));
|
||||
enable_irq(irq);
|
||||
}
|
||||
|
||||
static void bcsr_irq_mask(struct irq_data *d)
|
||||
{
|
||||
unsigned short v = 1 << (d->irq - bcsr_csc_base);
|
||||
__raw_writew(v, bcsr_virt + BCSR_REG_MASKCLR);
|
||||
wmb();
|
||||
}
|
||||
|
||||
static void bcsr_irq_maskack(struct irq_data *d)
|
||||
{
|
||||
unsigned short v = 1 << (d->irq - bcsr_csc_base);
|
||||
__raw_writew(v, bcsr_virt + BCSR_REG_MASKCLR);
|
||||
__raw_writew(v, bcsr_virt + BCSR_REG_INTSTAT); /* ack */
|
||||
wmb();
|
||||
}
|
||||
|
||||
static void bcsr_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
unsigned short v = 1 << (d->irq - bcsr_csc_base);
|
||||
__raw_writew(v, bcsr_virt + BCSR_REG_MASKSET);
|
||||
wmb();
|
||||
}
|
||||
|
||||
static struct irq_chip bcsr_irq_type = {
|
||||
.name = "CPLD",
|
||||
.irq_mask = bcsr_irq_mask,
|
||||
.irq_mask_ack = bcsr_irq_maskack,
|
||||
.irq_unmask = bcsr_irq_unmask,
|
||||
};
|
||||
|
||||
void __init bcsr_init_irq(int csc_start, int csc_end, int hook_irq)
|
||||
{
|
||||
unsigned int irq;
|
||||
|
||||
/* mask & enable & ack all */
|
||||
__raw_writew(0xffff, bcsr_virt + BCSR_REG_MASKCLR);
|
||||
__raw_writew(0xffff, bcsr_virt + BCSR_REG_INTSET);
|
||||
__raw_writew(0xffff, bcsr_virt + BCSR_REG_INTSTAT);
|
||||
wmb();
|
||||
|
||||
bcsr_csc_base = csc_start;
|
||||
|
||||
for (irq = csc_start; irq <= csc_end; irq++)
|
||||
irq_set_chip_and_handler_name(irq, &bcsr_irq_type,
|
||||
handle_level_irq, "level");
|
||||
|
||||
irq_set_chained_handler(hook_irq, bcsr_csc_handler);
|
||||
}
|
616
arch/mips/alchemy/devboards/db1000.c
Normal file
616
arch/mips/alchemy/devboards/db1000.c
Normal file
|
@ -0,0 +1,616 @@
|
|||
/*
|
||||
* DBAu1000/1500/1100 PBAu1100/1500 board support
|
||||
*
|
||||
* Copyright 2000, 2008 MontaVista Software Inc.
|
||||
* Author: MontaVista Software, Inc. <source@mvista.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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/spi_gpio.h>
|
||||
#include <linux/spi/ads7846.h>
|
||||
#include <asm/mach-au1x00/au1000.h>
|
||||
#include <asm/mach-au1x00/au1000_dma.h>
|
||||
#include <asm/mach-au1x00/au1100_mmc.h>
|
||||
#include <asm/mach-db1x00/bcsr.h>
|
||||
#include <asm/reboot.h>
|
||||
#include <prom.h>
|
||||
#include "platform.h"
|
||||
|
||||
#define F_SWAPPED (bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1000_SWAPBOOT)
|
||||
|
||||
const char *get_system_type(void);
|
||||
|
||||
int __init db1000_board_setup(void)
|
||||
{
|
||||
/* initialize board register space */
|
||||
bcsr_init(DB1000_BCSR_PHYS_ADDR,
|
||||
DB1000_BCSR_PHYS_ADDR + DB1000_BCSR_HEXLED_OFS);
|
||||
|
||||
switch (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI))) {
|
||||
case BCSR_WHOAMI_DB1000:
|
||||
case BCSR_WHOAMI_DB1500:
|
||||
case BCSR_WHOAMI_DB1100:
|
||||
case BCSR_WHOAMI_PB1500:
|
||||
case BCSR_WHOAMI_PB1500R2:
|
||||
case BCSR_WHOAMI_PB1100:
|
||||
pr_info("AMD Alchemy %s Board\n", get_system_type());
|
||||
return 0;
|
||||
}
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int db1500_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin)
|
||||
{
|
||||
if ((slot < 12) || (slot > 13) || pin == 0)
|
||||
return -1;
|
||||
if (slot == 12)
|
||||
return (pin == 1) ? AU1500_PCI_INTA : 0xff;
|
||||
if (slot == 13) {
|
||||
switch (pin) {
|
||||
case 1: return AU1500_PCI_INTA;
|
||||
case 2: return AU1500_PCI_INTB;
|
||||
case 3: return AU1500_PCI_INTC;
|
||||
case 4: return AU1500_PCI_INTD;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct resource alchemy_pci_host_res[] = {
|
||||
[0] = {
|
||||
.start = AU1500_PCI_PHYS_ADDR,
|
||||
.end = AU1500_PCI_PHYS_ADDR + 0xfff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct alchemy_pci_platdata db1500_pci_pd = {
|
||||
.board_map_irq = db1500_map_pci_irq,
|
||||
};
|
||||
|
||||
static struct platform_device db1500_pci_host_dev = {
|
||||
.dev.platform_data = &db1500_pci_pd,
|
||||
.name = "alchemy-pci",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(alchemy_pci_host_res),
|
||||
.resource = alchemy_pci_host_res,
|
||||
};
|
||||
|
||||
int __init db1500_pci_setup(void)
|
||||
{
|
||||
return platform_device_register(&db1500_pci_host_dev);
|
||||
}
|
||||
|
||||
static struct resource au1100_lcd_resources[] = {
|
||||
[0] = {
|
||||
.start = AU1100_LCD_PHYS_ADDR,
|
||||
.end = AU1100_LCD_PHYS_ADDR + 0x800 - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = AU1100_LCD_INT,
|
||||
.end = AU1100_LCD_INT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
}
|
||||
};
|
||||
|
||||
static u64 au1100_lcd_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
static struct platform_device au1100_lcd_device = {
|
||||
.name = "au1100-lcd",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.dma_mask = &au1100_lcd_dmamask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(au1100_lcd_resources),
|
||||
.resource = au1100_lcd_resources,
|
||||
};
|
||||
|
||||
static struct resource alchemy_ac97c_res[] = {
|
||||
[0] = {
|
||||
.start = AU1000_AC97_PHYS_ADDR,
|
||||
.end = AU1000_AC97_PHYS_ADDR + 0xfff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = DMA_ID_AC97C_TX,
|
||||
.end = DMA_ID_AC97C_TX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[2] = {
|
||||
.start = DMA_ID_AC97C_RX,
|
||||
.end = DMA_ID_AC97C_RX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device alchemy_ac97c_dev = {
|
||||
.name = "alchemy-ac97c",
|
||||
.id = -1,
|
||||
.resource = alchemy_ac97c_res,
|
||||
.num_resources = ARRAY_SIZE(alchemy_ac97c_res),
|
||||
};
|
||||
|
||||
static struct platform_device alchemy_ac97c_dma_dev = {
|
||||
.name = "alchemy-pcm-dma",
|
||||
.id = 0,
|
||||
};
|
||||
|
||||
static struct platform_device db1x00_codec_dev = {
|
||||
.name = "ac97-codec",
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
static struct platform_device db1x00_audio_dev = {
|
||||
.name = "db1000-audio",
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static irqreturn_t db1100_mmc_cd(int irq, void *ptr)
|
||||
{
|
||||
void (*mmc_cd)(struct mmc_host *, unsigned long);
|
||||
/* link against CONFIG_MMC=m */
|
||||
mmc_cd = symbol_get(mmc_detect_change);
|
||||
mmc_cd(ptr, msecs_to_jiffies(500));
|
||||
symbol_put(mmc_detect_change);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int db1100_mmc_cd_setup(void *mmc_host, int en)
|
||||
{
|
||||
int ret = 0, irq;
|
||||
|
||||
if (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI)) == BCSR_WHOAMI_DB1100)
|
||||
irq = AU1100_GPIO19_INT;
|
||||
else
|
||||
irq = AU1100_GPIO14_INT; /* PB1100 SD0 CD# */
|
||||
|
||||
if (en) {
|
||||
irq_set_irq_type(irq, IRQ_TYPE_EDGE_BOTH);
|
||||
ret = request_irq(irq, db1100_mmc_cd, 0,
|
||||
"sd0_cd", mmc_host);
|
||||
} else
|
||||
free_irq(irq, mmc_host);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int db1100_mmc1_cd_setup(void *mmc_host, int en)
|
||||
{
|
||||
int ret = 0, irq;
|
||||
|
||||
if (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI)) == BCSR_WHOAMI_DB1100)
|
||||
irq = AU1100_GPIO20_INT;
|
||||
else
|
||||
irq = AU1100_GPIO15_INT; /* PB1100 SD1 CD# */
|
||||
|
||||
if (en) {
|
||||
irq_set_irq_type(irq, IRQ_TYPE_EDGE_BOTH);
|
||||
ret = request_irq(irq, db1100_mmc_cd, 0,
|
||||
"sd1_cd", mmc_host);
|
||||
} else
|
||||
free_irq(irq, mmc_host);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int db1100_mmc_card_readonly(void *mmc_host)
|
||||
{
|
||||
/* testing suggests that this bit is inverted */
|
||||
return (bcsr_read(BCSR_STATUS) & BCSR_STATUS_SD0WP) ? 0 : 1;
|
||||
}
|
||||
|
||||
static int db1100_mmc_card_inserted(void *mmc_host)
|
||||
{
|
||||
return !alchemy_gpio_get_value(19);
|
||||
}
|
||||
|
||||
static void db1100_mmc_set_power(void *mmc_host, int state)
|
||||
{
|
||||
int bit;
|
||||
|
||||
if (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI)) == BCSR_WHOAMI_DB1100)
|
||||
bit = BCSR_BOARD_SD0PWR;
|
||||
else
|
||||
bit = BCSR_BOARD_PB1100_SD0PWR;
|
||||
|
||||
if (state) {
|
||||
bcsr_mod(BCSR_BOARD, 0, bit);
|
||||
msleep(400); /* stabilization time */
|
||||
} else
|
||||
bcsr_mod(BCSR_BOARD, bit, 0);
|
||||
}
|
||||
|
||||
static void db1100_mmcled_set(struct led_classdev *led, enum led_brightness b)
|
||||
{
|
||||
if (b != LED_OFF)
|
||||
bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED0, 0);
|
||||
else
|
||||
bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED0);
|
||||
}
|
||||
|
||||
static struct led_classdev db1100_mmc_led = {
|
||||
.brightness_set = db1100_mmcled_set,
|
||||
};
|
||||
|
||||
static int db1100_mmc1_card_readonly(void *mmc_host)
|
||||
{
|
||||
return (bcsr_read(BCSR_BOARD) & BCSR_BOARD_SD1WP) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int db1100_mmc1_card_inserted(void *mmc_host)
|
||||
{
|
||||
return !alchemy_gpio_get_value(20);
|
||||
}
|
||||
|
||||
static void db1100_mmc1_set_power(void *mmc_host, int state)
|
||||
{
|
||||
int bit;
|
||||
|
||||
if (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI)) == BCSR_WHOAMI_DB1100)
|
||||
bit = BCSR_BOARD_SD1PWR;
|
||||
else
|
||||
bit = BCSR_BOARD_PB1100_SD1PWR;
|
||||
|
||||
if (state) {
|
||||
bcsr_mod(BCSR_BOARD, 0, bit);
|
||||
msleep(400); /* stabilization time */
|
||||
} else
|
||||
bcsr_mod(BCSR_BOARD, bit, 0);
|
||||
}
|
||||
|
||||
static void db1100_mmc1led_set(struct led_classdev *led, enum led_brightness b)
|
||||
{
|
||||
if (b != LED_OFF)
|
||||
bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED1, 0);
|
||||
else
|
||||
bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED1);
|
||||
}
|
||||
|
||||
static struct led_classdev db1100_mmc1_led = {
|
||||
.brightness_set = db1100_mmc1led_set,
|
||||
};
|
||||
|
||||
static struct au1xmmc_platform_data db1100_mmc_platdata[2] = {
|
||||
[0] = {
|
||||
.cd_setup = db1100_mmc_cd_setup,
|
||||
.set_power = db1100_mmc_set_power,
|
||||
.card_inserted = db1100_mmc_card_inserted,
|
||||
.card_readonly = db1100_mmc_card_readonly,
|
||||
.led = &db1100_mmc_led,
|
||||
},
|
||||
[1] = {
|
||||
.cd_setup = db1100_mmc1_cd_setup,
|
||||
.set_power = db1100_mmc1_set_power,
|
||||
.card_inserted = db1100_mmc1_card_inserted,
|
||||
.card_readonly = db1100_mmc1_card_readonly,
|
||||
.led = &db1100_mmc1_led,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource au1100_mmc0_resources[] = {
|
||||
[0] = {
|
||||
.start = AU1100_SD0_PHYS_ADDR,
|
||||
.end = AU1100_SD0_PHYS_ADDR + 0xfff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = AU1100_SD_INT,
|
||||
.end = AU1100_SD_INT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[2] = {
|
||||
.start = DMA_ID_SD0_TX,
|
||||
.end = DMA_ID_SD0_TX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[3] = {
|
||||
.start = DMA_ID_SD0_RX,
|
||||
.end = DMA_ID_SD0_RX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
}
|
||||
};
|
||||
|
||||
static u64 au1xxx_mmc_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
static struct platform_device db1100_mmc0_dev = {
|
||||
.name = "au1xxx-mmc",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.dma_mask = &au1xxx_mmc_dmamask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
.platform_data = &db1100_mmc_platdata[0],
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(au1100_mmc0_resources),
|
||||
.resource = au1100_mmc0_resources,
|
||||
};
|
||||
|
||||
static struct resource au1100_mmc1_res[] = {
|
||||
[0] = {
|
||||
.start = AU1100_SD1_PHYS_ADDR,
|
||||
.end = AU1100_SD1_PHYS_ADDR + 0xfff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = AU1100_SD_INT,
|
||||
.end = AU1100_SD_INT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[2] = {
|
||||
.start = DMA_ID_SD1_TX,
|
||||
.end = DMA_ID_SD1_TX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[3] = {
|
||||
.start = DMA_ID_SD1_RX,
|
||||
.end = DMA_ID_SD1_RX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
}
|
||||
};
|
||||
|
||||
static struct platform_device db1100_mmc1_dev = {
|
||||
.name = "au1xxx-mmc",
|
||||
.id = 1,
|
||||
.dev = {
|
||||
.dma_mask = &au1xxx_mmc_dmamask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
.platform_data = &db1100_mmc_platdata[1],
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(au1100_mmc1_res),
|
||||
.resource = au1100_mmc1_res,
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void db1000_irda_set_phy_mode(int mode)
|
||||
{
|
||||
unsigned short mask = BCSR_RESETS_IRDA_MODE_MASK | BCSR_RESETS_FIR_SEL;
|
||||
|
||||
switch (mode) {
|
||||
case AU1000_IRDA_PHY_MODE_OFF:
|
||||
bcsr_mod(BCSR_RESETS, mask, BCSR_RESETS_IRDA_MODE_OFF);
|
||||
break;
|
||||
case AU1000_IRDA_PHY_MODE_SIR:
|
||||
bcsr_mod(BCSR_RESETS, mask, BCSR_RESETS_IRDA_MODE_FULL);
|
||||
break;
|
||||
case AU1000_IRDA_PHY_MODE_FIR:
|
||||
bcsr_mod(BCSR_RESETS, mask, BCSR_RESETS_IRDA_MODE_FULL |
|
||||
BCSR_RESETS_FIR_SEL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct au1k_irda_platform_data db1000_irda_platdata = {
|
||||
.set_phy_mode = db1000_irda_set_phy_mode,
|
||||
};
|
||||
|
||||
static struct resource au1000_irda_res[] = {
|
||||
[0] = {
|
||||
.start = AU1000_IRDA_PHYS_ADDR,
|
||||
.end = AU1000_IRDA_PHYS_ADDR + 0x0fff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = AU1000_IRDA_TX_INT,
|
||||
.end = AU1000_IRDA_TX_INT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[2] = {
|
||||
.start = AU1000_IRDA_RX_INT,
|
||||
.end = AU1000_IRDA_RX_INT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device db1000_irda_dev = {
|
||||
.name = "au1000-irda",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.platform_data = &db1000_irda_platdata,
|
||||
},
|
||||
.resource = au1000_irda_res,
|
||||
.num_resources = ARRAY_SIZE(au1000_irda_res),
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static struct ads7846_platform_data db1100_touch_pd = {
|
||||
.model = 7846,
|
||||
.vref_mv = 3300,
|
||||
.gpio_pendown = 21,
|
||||
};
|
||||
|
||||
static struct spi_gpio_platform_data db1100_spictl_pd = {
|
||||
.sck = 209,
|
||||
.mosi = 208,
|
||||
.miso = 207,
|
||||
.num_chipselect = 1,
|
||||
};
|
||||
|
||||
static struct spi_board_info db1100_spi_info[] __initdata = {
|
||||
[0] = {
|
||||
.modalias = "ads7846",
|
||||
.max_speed_hz = 3250000,
|
||||
.bus_num = 0,
|
||||
.chip_select = 0,
|
||||
.mode = 0,
|
||||
.irq = AU1100_GPIO21_INT,
|
||||
.platform_data = &db1100_touch_pd,
|
||||
.controller_data = (void *)210, /* for spi_gpio: CS# GPIO210 */
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device db1100_spi_dev = {
|
||||
.name = "spi_gpio",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.platform_data = &db1100_spictl_pd,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
static struct platform_device *db1x00_devs[] = {
|
||||
&db1x00_codec_dev,
|
||||
&alchemy_ac97c_dma_dev,
|
||||
&alchemy_ac97c_dev,
|
||||
&db1x00_audio_dev,
|
||||
};
|
||||
|
||||
static struct platform_device *db1000_devs[] = {
|
||||
&db1000_irda_dev,
|
||||
};
|
||||
|
||||
static struct platform_device *db1100_devs[] = {
|
||||
&au1100_lcd_device,
|
||||
&db1100_mmc0_dev,
|
||||
&db1100_mmc1_dev,
|
||||
&db1000_irda_dev,
|
||||
};
|
||||
|
||||
int __init db1000_dev_setup(void)
|
||||
{
|
||||
int board = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI));
|
||||
int c0, c1, d0, d1, s0, s1, flashsize = 32, twosocks = 1;
|
||||
unsigned long pfc;
|
||||
struct clk *c, *p;
|
||||
|
||||
if (board == BCSR_WHOAMI_DB1500) {
|
||||
c0 = AU1500_GPIO2_INT;
|
||||
c1 = AU1500_GPIO5_INT;
|
||||
d0 = AU1500_GPIO0_INT;
|
||||
d1 = AU1500_GPIO3_INT;
|
||||
s0 = AU1500_GPIO1_INT;
|
||||
s1 = AU1500_GPIO4_INT;
|
||||
} else if (board == BCSR_WHOAMI_DB1100) {
|
||||
c0 = AU1100_GPIO2_INT;
|
||||
c1 = AU1100_GPIO5_INT;
|
||||
d0 = AU1100_GPIO0_INT;
|
||||
d1 = AU1100_GPIO3_INT;
|
||||
s0 = AU1100_GPIO1_INT;
|
||||
s1 = AU1100_GPIO4_INT;
|
||||
|
||||
gpio_request(19, "sd0_cd");
|
||||
gpio_request(20, "sd1_cd");
|
||||
gpio_direction_input(19); /* sd0 cd# */
|
||||
gpio_direction_input(20); /* sd1 cd# */
|
||||
|
||||
/* spi_gpio on SSI0 pins */
|
||||
pfc = alchemy_rdsys(AU1000_SYS_PINFUNC);
|
||||
pfc |= (1 << 0); /* SSI0 pins as GPIOs */
|
||||
alchemy_wrsys(pfc, AU1000_SYS_PINFUNC);
|
||||
|
||||
spi_register_board_info(db1100_spi_info,
|
||||
ARRAY_SIZE(db1100_spi_info));
|
||||
|
||||
/* link LCD clock to AUXPLL */
|
||||
p = clk_get(NULL, "auxpll_clk");
|
||||
c = clk_get(NULL, "lcd_intclk");
|
||||
if (!IS_ERR(c) && !IS_ERR(p)) {
|
||||
clk_set_parent(c, p);
|
||||
clk_set_rate(c, clk_get_rate(p));
|
||||
}
|
||||
if (!IS_ERR(c))
|
||||
clk_put(c);
|
||||
if (!IS_ERR(p))
|
||||
clk_put(p);
|
||||
|
||||
platform_add_devices(db1100_devs, ARRAY_SIZE(db1100_devs));
|
||||
platform_device_register(&db1100_spi_dev);
|
||||
} else if (board == BCSR_WHOAMI_DB1000) {
|
||||
c0 = AU1000_GPIO2_INT;
|
||||
c1 = AU1000_GPIO5_INT;
|
||||
d0 = AU1000_GPIO0_INT;
|
||||
d1 = AU1000_GPIO3_INT;
|
||||
s0 = AU1000_GPIO1_INT;
|
||||
s1 = AU1000_GPIO4_INT;
|
||||
platform_add_devices(db1000_devs, ARRAY_SIZE(db1000_devs));
|
||||
} else if ((board == BCSR_WHOAMI_PB1500) ||
|
||||
(board == BCSR_WHOAMI_PB1500R2)) {
|
||||
c0 = AU1500_GPIO203_INT;
|
||||
d0 = AU1500_GPIO201_INT;
|
||||
s0 = AU1500_GPIO202_INT;
|
||||
twosocks = 0;
|
||||
flashsize = 64;
|
||||
/* RTC and daughtercard irqs */
|
||||
irq_set_irq_type(AU1500_GPIO204_INT, IRQ_TYPE_LEVEL_LOW);
|
||||
irq_set_irq_type(AU1500_GPIO205_INT, IRQ_TYPE_LEVEL_LOW);
|
||||
/* EPSON S1D13806 0x1b000000
|
||||
* SRAM 1MB/2MB 0x1a000000
|
||||
* DS1693 RTC 0x0c000000
|
||||
*/
|
||||
} else if (board == BCSR_WHOAMI_PB1100) {
|
||||
c0 = AU1100_GPIO11_INT;
|
||||
d0 = AU1100_GPIO9_INT;
|
||||
s0 = AU1100_GPIO10_INT;
|
||||
twosocks = 0;
|
||||
flashsize = 64;
|
||||
/* pendown, rtc, daughtercard irqs */
|
||||
irq_set_irq_type(AU1100_GPIO8_INT, IRQ_TYPE_LEVEL_LOW);
|
||||
irq_set_irq_type(AU1100_GPIO12_INT, IRQ_TYPE_LEVEL_LOW);
|
||||
irq_set_irq_type(AU1100_GPIO13_INT, IRQ_TYPE_LEVEL_LOW);
|
||||
/* EPSON S1D13806 0x1b000000
|
||||
* SRAM 1MB/2MB 0x1a000000
|
||||
* DiskOnChip 0x0d000000
|
||||
* DS1693 RTC 0x0c000000
|
||||
*/
|
||||
platform_add_devices(db1100_devs, ARRAY_SIZE(db1100_devs));
|
||||
} else
|
||||
return 0; /* unknown board, no further dev setup to do */
|
||||
|
||||
irq_set_irq_type(d0, IRQ_TYPE_EDGE_BOTH);
|
||||
irq_set_irq_type(c0, IRQ_TYPE_LEVEL_LOW);
|
||||
irq_set_irq_type(s0, IRQ_TYPE_LEVEL_LOW);
|
||||
|
||||
db1x_register_pcmcia_socket(
|
||||
AU1000_PCMCIA_ATTR_PHYS_ADDR,
|
||||
AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
|
||||
AU1000_PCMCIA_MEM_PHYS_ADDR,
|
||||
AU1000_PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1,
|
||||
AU1000_PCMCIA_IO_PHYS_ADDR,
|
||||
AU1000_PCMCIA_IO_PHYS_ADDR + 0x000010000 - 1,
|
||||
c0, d0, /*s0*/0, 0, 0);
|
||||
|
||||
if (twosocks) {
|
||||
irq_set_irq_type(d1, IRQ_TYPE_EDGE_BOTH);
|
||||
irq_set_irq_type(c1, IRQ_TYPE_LEVEL_LOW);
|
||||
irq_set_irq_type(s1, IRQ_TYPE_LEVEL_LOW);
|
||||
|
||||
db1x_register_pcmcia_socket(
|
||||
AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004000000,
|
||||
AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004400000 - 1,
|
||||
AU1000_PCMCIA_MEM_PHYS_ADDR + 0x004000000,
|
||||
AU1000_PCMCIA_MEM_PHYS_ADDR + 0x004400000 - 1,
|
||||
AU1000_PCMCIA_IO_PHYS_ADDR + 0x004000000,
|
||||
AU1000_PCMCIA_IO_PHYS_ADDR + 0x004010000 - 1,
|
||||
c1, d1, /*s1*/0, 0, 1);
|
||||
}
|
||||
|
||||
platform_add_devices(db1x00_devs, ARRAY_SIZE(db1x00_devs));
|
||||
db1x_register_norflash(flashsize << 20, 4 /* 32bit */, F_SWAPPED);
|
||||
return 0;
|
||||
}
|
961
arch/mips/alchemy/devboards/db1200.c
Normal file
961
arch/mips/alchemy/devboards/db1200.c
Normal file
|
@ -0,0 +1,961 @@
|
|||
/*
|
||||
* DBAu1200/PBAu1200 board platform device registration
|
||||
*
|
||||
* Copyright (C) 2008-2011 Manuel Lauss
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/flash.h>
|
||||
#include <linux/smc91x.h>
|
||||
#include <linux/ata_platform.h>
|
||||
#include <asm/mach-au1x00/au1000.h>
|
||||
#include <asm/mach-au1x00/au1100_mmc.h>
|
||||
#include <asm/mach-au1x00/au1xxx_dbdma.h>
|
||||
#include <asm/mach-au1x00/au1xxx_psc.h>
|
||||
#include <asm/mach-au1x00/au1200fb.h>
|
||||
#include <asm/mach-au1x00/au1550_spi.h>
|
||||
#include <asm/mach-db1x00/bcsr.h>
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#define BCSR_INT_IDE 0x0001
|
||||
#define BCSR_INT_ETH 0x0002
|
||||
#define BCSR_INT_PC0 0x0004
|
||||
#define BCSR_INT_PC0STSCHG 0x0008
|
||||
#define BCSR_INT_PC1 0x0010
|
||||
#define BCSR_INT_PC1STSCHG 0x0020
|
||||
#define BCSR_INT_DC 0x0040
|
||||
#define BCSR_INT_FLASHBUSY 0x0080
|
||||
#define BCSR_INT_PC0INSERT 0x0100
|
||||
#define BCSR_INT_PC0EJECT 0x0200
|
||||
#define BCSR_INT_PC1INSERT 0x0400
|
||||
#define BCSR_INT_PC1EJECT 0x0800
|
||||
#define BCSR_INT_SD0INSERT 0x1000
|
||||
#define BCSR_INT_SD0EJECT 0x2000
|
||||
#define BCSR_INT_SD1INSERT 0x4000
|
||||
#define BCSR_INT_SD1EJECT 0x8000
|
||||
|
||||
#define DB1200_IDE_PHYS_ADDR 0x18800000
|
||||
#define DB1200_IDE_REG_SHIFT 5
|
||||
#define DB1200_IDE_PHYS_LEN (16 << DB1200_IDE_REG_SHIFT)
|
||||
#define DB1200_ETH_PHYS_ADDR 0x19000300
|
||||
#define DB1200_NAND_PHYS_ADDR 0x20000000
|
||||
|
||||
#define PB1200_IDE_PHYS_ADDR 0x0C800000
|
||||
#define PB1200_ETH_PHYS_ADDR 0x0D000300
|
||||
#define PB1200_NAND_PHYS_ADDR 0x1C000000
|
||||
|
||||
#define DB1200_INT_BEGIN (AU1000_MAX_INTR + 1)
|
||||
#define DB1200_IDE_INT (DB1200_INT_BEGIN + 0)
|
||||
#define DB1200_ETH_INT (DB1200_INT_BEGIN + 1)
|
||||
#define DB1200_PC0_INT (DB1200_INT_BEGIN + 2)
|
||||
#define DB1200_PC0_STSCHG_INT (DB1200_INT_BEGIN + 3)
|
||||
#define DB1200_PC1_INT (DB1200_INT_BEGIN + 4)
|
||||
#define DB1200_PC1_STSCHG_INT (DB1200_INT_BEGIN + 5)
|
||||
#define DB1200_DC_INT (DB1200_INT_BEGIN + 6)
|
||||
#define DB1200_FLASHBUSY_INT (DB1200_INT_BEGIN + 7)
|
||||
#define DB1200_PC0_INSERT_INT (DB1200_INT_BEGIN + 8)
|
||||
#define DB1200_PC0_EJECT_INT (DB1200_INT_BEGIN + 9)
|
||||
#define DB1200_PC1_INSERT_INT (DB1200_INT_BEGIN + 10)
|
||||
#define DB1200_PC1_EJECT_INT (DB1200_INT_BEGIN + 11)
|
||||
#define DB1200_SD0_INSERT_INT (DB1200_INT_BEGIN + 12)
|
||||
#define DB1200_SD0_EJECT_INT (DB1200_INT_BEGIN + 13)
|
||||
#define PB1200_SD1_INSERT_INT (DB1200_INT_BEGIN + 14)
|
||||
#define PB1200_SD1_EJECT_INT (DB1200_INT_BEGIN + 15)
|
||||
#define DB1200_INT_END (DB1200_INT_BEGIN + 15)
|
||||
|
||||
const char *get_system_type(void);
|
||||
|
||||
static int __init db1200_detect_board(void)
|
||||
{
|
||||
int bid;
|
||||
|
||||
/* try the DB1200 first */
|
||||
bcsr_init(DB1200_BCSR_PHYS_ADDR,
|
||||
DB1200_BCSR_PHYS_ADDR + DB1200_BCSR_HEXLED_OFS);
|
||||
if (BCSR_WHOAMI_DB1200 == BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI))) {
|
||||
unsigned short t = bcsr_read(BCSR_HEXLEDS);
|
||||
bcsr_write(BCSR_HEXLEDS, ~t);
|
||||
if (bcsr_read(BCSR_HEXLEDS) != t) {
|
||||
bcsr_write(BCSR_HEXLEDS, t);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* okay, try the PB1200 then */
|
||||
bcsr_init(PB1200_BCSR_PHYS_ADDR,
|
||||
PB1200_BCSR_PHYS_ADDR + PB1200_BCSR_HEXLED_OFS);
|
||||
bid = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI));
|
||||
if ((bid == BCSR_WHOAMI_PB1200_DDR1) ||
|
||||
(bid == BCSR_WHOAMI_PB1200_DDR2)) {
|
||||
unsigned short t = bcsr_read(BCSR_HEXLEDS);
|
||||
bcsr_write(BCSR_HEXLEDS, ~t);
|
||||
if (bcsr_read(BCSR_HEXLEDS) != t) {
|
||||
bcsr_write(BCSR_HEXLEDS, t);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1; /* it's neither */
|
||||
}
|
||||
|
||||
int __init db1200_board_setup(void)
|
||||
{
|
||||
unsigned short whoami;
|
||||
|
||||
if (db1200_detect_board())
|
||||
return -ENODEV;
|
||||
|
||||
whoami = bcsr_read(BCSR_WHOAMI);
|
||||
switch (BCSR_WHOAMI_BOARD(whoami)) {
|
||||
case BCSR_WHOAMI_PB1200_DDR1:
|
||||
case BCSR_WHOAMI_PB1200_DDR2:
|
||||
case BCSR_WHOAMI_DB1200:
|
||||
break;
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "Alchemy/AMD/RMI %s Board, CPLD Rev %d"
|
||||
" Board-ID %d Daughtercard ID %d\n", get_system_type(),
|
||||
(whoami >> 4) & 0xf, (whoami >> 8) & 0xf, whoami & 0xf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static struct mtd_partition db1200_spiflash_parts[] = {
|
||||
{
|
||||
.name = "spi_flash",
|
||||
.offset = 0,
|
||||
.size = MTDPART_SIZ_FULL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct flash_platform_data db1200_spiflash_data = {
|
||||
.name = "s25fl001",
|
||||
.parts = db1200_spiflash_parts,
|
||||
.nr_parts = ARRAY_SIZE(db1200_spiflash_parts),
|
||||
.type = "m25p10",
|
||||
};
|
||||
|
||||
static struct spi_board_info db1200_spi_devs[] __initdata = {
|
||||
{
|
||||
/* TI TMP121AIDBVR temp sensor */
|
||||
.modalias = "tmp121",
|
||||
.max_speed_hz = 2000000,
|
||||
.bus_num = 0,
|
||||
.chip_select = 0,
|
||||
.mode = 0,
|
||||
},
|
||||
{
|
||||
/* Spansion S25FL001D0FMA SPI flash */
|
||||
.modalias = "m25p80",
|
||||
.max_speed_hz = 50000000,
|
||||
.bus_num = 0,
|
||||
.chip_select = 1,
|
||||
.mode = 0,
|
||||
.platform_data = &db1200_spiflash_data,
|
||||
},
|
||||
};
|
||||
|
||||
static struct i2c_board_info db1200_i2c_devs[] __initdata = {
|
||||
{ I2C_BOARD_INFO("24c04", 0x52), }, /* AT24C04-10 I2C eeprom */
|
||||
{ I2C_BOARD_INFO("ne1619", 0x2d), }, /* adm1025-compat hwmon */
|
||||
{ I2C_BOARD_INFO("wm8731", 0x1b), }, /* I2S audio codec WM8731 */
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static void au1200_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
unsigned long ioaddr = (unsigned long)this->IO_ADDR_W;
|
||||
|
||||
ioaddr &= 0xffffff00;
|
||||
|
||||
if (ctrl & NAND_CLE) {
|
||||
ioaddr += MEM_STNAND_CMD;
|
||||
} else if (ctrl & NAND_ALE) {
|
||||
ioaddr += MEM_STNAND_ADDR;
|
||||
} else {
|
||||
/* assume we want to r/w real data by default */
|
||||
ioaddr += MEM_STNAND_DATA;
|
||||
}
|
||||
this->IO_ADDR_R = this->IO_ADDR_W = (void __iomem *)ioaddr;
|
||||
if (cmd != NAND_CMD_NONE) {
|
||||
__raw_writeb(cmd, this->IO_ADDR_W);
|
||||
wmb();
|
||||
}
|
||||
}
|
||||
|
||||
static int au1200_nand_device_ready(struct mtd_info *mtd)
|
||||
{
|
||||
return alchemy_rdsmem(AU1000_MEM_STSTAT) & 1;
|
||||
}
|
||||
|
||||
static struct mtd_partition db1200_nand_parts[] = {
|
||||
{
|
||||
.name = "NAND FS 0",
|
||||
.offset = 0,
|
||||
.size = 8 * 1024 * 1024,
|
||||
},
|
||||
{
|
||||
.name = "NAND FS 1",
|
||||
.offset = MTDPART_OFS_APPEND,
|
||||
.size = MTDPART_SIZ_FULL
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_nand_data db1200_nand_platdata = {
|
||||
.chip = {
|
||||
.nr_chips = 1,
|
||||
.chip_offset = 0,
|
||||
.nr_partitions = ARRAY_SIZE(db1200_nand_parts),
|
||||
.partitions = db1200_nand_parts,
|
||||
.chip_delay = 20,
|
||||
},
|
||||
.ctrl = {
|
||||
.dev_ready = au1200_nand_device_ready,
|
||||
.cmd_ctrl = au1200_nand_cmd_ctrl,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource db1200_nand_res[] = {
|
||||
[0] = {
|
||||
.start = DB1200_NAND_PHYS_ADDR,
|
||||
.end = DB1200_NAND_PHYS_ADDR + 0xff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device db1200_nand_dev = {
|
||||
.name = "gen_nand",
|
||||
.num_resources = ARRAY_SIZE(db1200_nand_res),
|
||||
.resource = db1200_nand_res,
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.platform_data = &db1200_nand_platdata,
|
||||
}
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static struct smc91x_platdata db1200_eth_data = {
|
||||
.flags = SMC91X_NOWAIT | SMC91X_USE_16BIT,
|
||||
.leda = RPC_LED_100_10,
|
||||
.ledb = RPC_LED_TX_RX,
|
||||
};
|
||||
|
||||
static struct resource db1200_eth_res[] = {
|
||||
[0] = {
|
||||
.start = DB1200_ETH_PHYS_ADDR,
|
||||
.end = DB1200_ETH_PHYS_ADDR + 0xf,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = DB1200_ETH_INT,
|
||||
.end = DB1200_ETH_INT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device db1200_eth_dev = {
|
||||
.dev = {
|
||||
.platform_data = &db1200_eth_data,
|
||||
},
|
||||
.name = "smc91x",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(db1200_eth_res),
|
||||
.resource = db1200_eth_res,
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static struct pata_platform_info db1200_ide_info = {
|
||||
.ioport_shift = DB1200_IDE_REG_SHIFT,
|
||||
};
|
||||
|
||||
#define IDE_ALT_START (14 << DB1200_IDE_REG_SHIFT)
|
||||
static struct resource db1200_ide_res[] = {
|
||||
[0] = {
|
||||
.start = DB1200_IDE_PHYS_ADDR,
|
||||
.end = DB1200_IDE_PHYS_ADDR + IDE_ALT_START - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = DB1200_IDE_PHYS_ADDR + IDE_ALT_START,
|
||||
.end = DB1200_IDE_PHYS_ADDR + DB1200_IDE_PHYS_LEN - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[2] = {
|
||||
.start = DB1200_IDE_INT,
|
||||
.end = DB1200_IDE_INT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static u64 au1200_ide_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
static struct platform_device db1200_ide_dev = {
|
||||
.name = "pata_platform",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.dma_mask = &au1200_ide_dmamask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
.platform_data = &db1200_ide_info,
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(db1200_ide_res),
|
||||
.resource = db1200_ide_res,
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/* SD carddetects: they're supposed to be edge-triggered, but ack
|
||||
* doesn't seem to work (CPLD Rev 2). Instead, the screaming one
|
||||
* is disabled and its counterpart enabled. The 500ms timeout is
|
||||
* because the carddetect isn't debounced in hardware.
|
||||
*/
|
||||
static irqreturn_t db1200_mmc_cd(int irq, void *ptr)
|
||||
{
|
||||
void(*mmc_cd)(struct mmc_host *, unsigned long);
|
||||
|
||||
if (irq == DB1200_SD0_INSERT_INT) {
|
||||
disable_irq_nosync(DB1200_SD0_INSERT_INT);
|
||||
enable_irq(DB1200_SD0_EJECT_INT);
|
||||
} else {
|
||||
disable_irq_nosync(DB1200_SD0_EJECT_INT);
|
||||
enable_irq(DB1200_SD0_INSERT_INT);
|
||||
}
|
||||
|
||||
/* link against CONFIG_MMC=m */
|
||||
mmc_cd = symbol_get(mmc_detect_change);
|
||||
if (mmc_cd) {
|
||||
mmc_cd(ptr, msecs_to_jiffies(500));
|
||||
symbol_put(mmc_detect_change);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int db1200_mmc_cd_setup(void *mmc_host, int en)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (en) {
|
||||
ret = request_irq(DB1200_SD0_INSERT_INT, db1200_mmc_cd,
|
||||
0, "sd_insert", mmc_host);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = request_irq(DB1200_SD0_EJECT_INT, db1200_mmc_cd,
|
||||
0, "sd_eject", mmc_host);
|
||||
if (ret) {
|
||||
free_irq(DB1200_SD0_INSERT_INT, mmc_host);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (bcsr_read(BCSR_SIGSTAT) & BCSR_INT_SD0INSERT)
|
||||
enable_irq(DB1200_SD0_EJECT_INT);
|
||||
else
|
||||
enable_irq(DB1200_SD0_INSERT_INT);
|
||||
|
||||
} else {
|
||||
free_irq(DB1200_SD0_INSERT_INT, mmc_host);
|
||||
free_irq(DB1200_SD0_EJECT_INT, mmc_host);
|
||||
}
|
||||
ret = 0;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void db1200_mmc_set_power(void *mmc_host, int state)
|
||||
{
|
||||
if (state) {
|
||||
bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_SD0PWR);
|
||||
msleep(400); /* stabilization time */
|
||||
} else
|
||||
bcsr_mod(BCSR_BOARD, BCSR_BOARD_SD0PWR, 0);
|
||||
}
|
||||
|
||||
static int db1200_mmc_card_readonly(void *mmc_host)
|
||||
{
|
||||
return (bcsr_read(BCSR_STATUS) & BCSR_STATUS_SD0WP) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int db1200_mmc_card_inserted(void *mmc_host)
|
||||
{
|
||||
return (bcsr_read(BCSR_SIGSTAT) & BCSR_INT_SD0INSERT) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void db1200_mmcled_set(struct led_classdev *led,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
if (brightness != LED_OFF)
|
||||
bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED0, 0);
|
||||
else
|
||||
bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED0);
|
||||
}
|
||||
|
||||
static struct led_classdev db1200_mmc_led = {
|
||||
.brightness_set = db1200_mmcled_set,
|
||||
};
|
||||
|
||||
/* -- */
|
||||
|
||||
static irqreturn_t pb1200_mmc1_cd(int irq, void *ptr)
|
||||
{
|
||||
void(*mmc_cd)(struct mmc_host *, unsigned long);
|
||||
|
||||
if (irq == PB1200_SD1_INSERT_INT) {
|
||||
disable_irq_nosync(PB1200_SD1_INSERT_INT);
|
||||
enable_irq(PB1200_SD1_EJECT_INT);
|
||||
} else {
|
||||
disable_irq_nosync(PB1200_SD1_EJECT_INT);
|
||||
enable_irq(PB1200_SD1_INSERT_INT);
|
||||
}
|
||||
|
||||
/* link against CONFIG_MMC=m */
|
||||
mmc_cd = symbol_get(mmc_detect_change);
|
||||
if (mmc_cd) {
|
||||
mmc_cd(ptr, msecs_to_jiffies(500));
|
||||
symbol_put(mmc_detect_change);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int pb1200_mmc1_cd_setup(void *mmc_host, int en)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (en) {
|
||||
ret = request_irq(PB1200_SD1_INSERT_INT, pb1200_mmc1_cd, 0,
|
||||
"sd1_insert", mmc_host);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = request_irq(PB1200_SD1_EJECT_INT, pb1200_mmc1_cd, 0,
|
||||
"sd1_eject", mmc_host);
|
||||
if (ret) {
|
||||
free_irq(PB1200_SD1_INSERT_INT, mmc_host);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (bcsr_read(BCSR_SIGSTAT) & BCSR_INT_SD1INSERT)
|
||||
enable_irq(PB1200_SD1_EJECT_INT);
|
||||
else
|
||||
enable_irq(PB1200_SD1_INSERT_INT);
|
||||
|
||||
} else {
|
||||
free_irq(PB1200_SD1_INSERT_INT, mmc_host);
|
||||
free_irq(PB1200_SD1_EJECT_INT, mmc_host);
|
||||
}
|
||||
ret = 0;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void pb1200_mmc1led_set(struct led_classdev *led,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
if (brightness != LED_OFF)
|
||||
bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED1, 0);
|
||||
else
|
||||
bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED1);
|
||||
}
|
||||
|
||||
static struct led_classdev pb1200_mmc1_led = {
|
||||
.brightness_set = pb1200_mmc1led_set,
|
||||
};
|
||||
|
||||
static void pb1200_mmc1_set_power(void *mmc_host, int state)
|
||||
{
|
||||
if (state) {
|
||||
bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_SD1PWR);
|
||||
msleep(400); /* stabilization time */
|
||||
} else
|
||||
bcsr_mod(BCSR_BOARD, BCSR_BOARD_SD1PWR, 0);
|
||||
}
|
||||
|
||||
static int pb1200_mmc1_card_readonly(void *mmc_host)
|
||||
{
|
||||
return (bcsr_read(BCSR_STATUS) & BCSR_STATUS_SD1WP) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int pb1200_mmc1_card_inserted(void *mmc_host)
|
||||
{
|
||||
return (bcsr_read(BCSR_SIGSTAT) & BCSR_INT_SD1INSERT) ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
static struct au1xmmc_platform_data db1200_mmc_platdata[2] = {
|
||||
[0] = {
|
||||
.cd_setup = db1200_mmc_cd_setup,
|
||||
.set_power = db1200_mmc_set_power,
|
||||
.card_inserted = db1200_mmc_card_inserted,
|
||||
.card_readonly = db1200_mmc_card_readonly,
|
||||
.led = &db1200_mmc_led,
|
||||
},
|
||||
[1] = {
|
||||
.cd_setup = pb1200_mmc1_cd_setup,
|
||||
.set_power = pb1200_mmc1_set_power,
|
||||
.card_inserted = pb1200_mmc1_card_inserted,
|
||||
.card_readonly = pb1200_mmc1_card_readonly,
|
||||
.led = &pb1200_mmc1_led,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource au1200_mmc0_resources[] = {
|
||||
[0] = {
|
||||
.start = AU1100_SD0_PHYS_ADDR,
|
||||
.end = AU1100_SD0_PHYS_ADDR + 0xfff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = AU1200_SD_INT,
|
||||
.end = AU1200_SD_INT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[2] = {
|
||||
.start = AU1200_DSCR_CMD0_SDMS_TX0,
|
||||
.end = AU1200_DSCR_CMD0_SDMS_TX0,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[3] = {
|
||||
.start = AU1200_DSCR_CMD0_SDMS_RX0,
|
||||
.end = AU1200_DSCR_CMD0_SDMS_RX0,
|
||||
.flags = IORESOURCE_DMA,
|
||||
}
|
||||
};
|
||||
|
||||
static u64 au1xxx_mmc_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
static struct platform_device db1200_mmc0_dev = {
|
||||
.name = "au1xxx-mmc",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.dma_mask = &au1xxx_mmc_dmamask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
.platform_data = &db1200_mmc_platdata[0],
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(au1200_mmc0_resources),
|
||||
.resource = au1200_mmc0_resources,
|
||||
};
|
||||
|
||||
static struct resource au1200_mmc1_res[] = {
|
||||
[0] = {
|
||||
.start = AU1100_SD1_PHYS_ADDR,
|
||||
.end = AU1100_SD1_PHYS_ADDR + 0xfff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = AU1200_SD_INT,
|
||||
.end = AU1200_SD_INT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[2] = {
|
||||
.start = AU1200_DSCR_CMD0_SDMS_TX1,
|
||||
.end = AU1200_DSCR_CMD0_SDMS_TX1,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[3] = {
|
||||
.start = AU1200_DSCR_CMD0_SDMS_RX1,
|
||||
.end = AU1200_DSCR_CMD0_SDMS_RX1,
|
||||
.flags = IORESOURCE_DMA,
|
||||
}
|
||||
};
|
||||
|
||||
static struct platform_device pb1200_mmc1_dev = {
|
||||
.name = "au1xxx-mmc",
|
||||
.id = 1,
|
||||
.dev = {
|
||||
.dma_mask = &au1xxx_mmc_dmamask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
.platform_data = &db1200_mmc_platdata[1],
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(au1200_mmc1_res),
|
||||
.resource = au1200_mmc1_res,
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static int db1200fb_panel_index(void)
|
||||
{
|
||||
return (bcsr_read(BCSR_SWITCHES) >> 8) & 0x0f;
|
||||
}
|
||||
|
||||
static int db1200fb_panel_init(void)
|
||||
{
|
||||
/* Apply power */
|
||||
bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD |
|
||||
BCSR_BOARD_LCDBL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int db1200fb_panel_shutdown(void)
|
||||
{
|
||||
/* Remove power */
|
||||
bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD |
|
||||
BCSR_BOARD_LCDBL, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct au1200fb_platdata db1200fb_pd = {
|
||||
.panel_index = db1200fb_panel_index,
|
||||
.panel_init = db1200fb_panel_init,
|
||||
.panel_shutdown = db1200fb_panel_shutdown,
|
||||
};
|
||||
|
||||
static struct resource au1200_lcd_res[] = {
|
||||
[0] = {
|
||||
.start = AU1200_LCD_PHYS_ADDR,
|
||||
.end = AU1200_LCD_PHYS_ADDR + 0x800 - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = AU1200_LCD_INT,
|
||||
.end = AU1200_LCD_INT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
}
|
||||
};
|
||||
|
||||
static u64 au1200_lcd_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
static struct platform_device au1200_lcd_dev = {
|
||||
.name = "au1200-lcd",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.dma_mask = &au1200_lcd_dmamask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
.platform_data = &db1200fb_pd,
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(au1200_lcd_res),
|
||||
.resource = au1200_lcd_res,
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static struct resource au1200_psc0_res[] = {
|
||||
[0] = {
|
||||
.start = AU1550_PSC0_PHYS_ADDR,
|
||||
.end = AU1550_PSC0_PHYS_ADDR + 0xfff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = AU1200_PSC0_INT,
|
||||
.end = AU1200_PSC0_INT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[2] = {
|
||||
.start = AU1200_DSCR_CMD0_PSC0_TX,
|
||||
.end = AU1200_DSCR_CMD0_PSC0_TX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[3] = {
|
||||
.start = AU1200_DSCR_CMD0_PSC0_RX,
|
||||
.end = AU1200_DSCR_CMD0_PSC0_RX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device db1200_i2c_dev = {
|
||||
.name = "au1xpsc_smbus",
|
||||
.id = 0, /* bus number */
|
||||
.num_resources = ARRAY_SIZE(au1200_psc0_res),
|
||||
.resource = au1200_psc0_res,
|
||||
};
|
||||
|
||||
static void db1200_spi_cs_en(struct au1550_spi_info *spi, int cs, int pol)
|
||||
{
|
||||
if (cs)
|
||||
bcsr_mod(BCSR_RESETS, 0, BCSR_RESETS_SPISEL);
|
||||
else
|
||||
bcsr_mod(BCSR_RESETS, BCSR_RESETS_SPISEL, 0);
|
||||
}
|
||||
|
||||
static struct au1550_spi_info db1200_spi_platdata = {
|
||||
.mainclk_hz = 50000000, /* PSC0 clock */
|
||||
.num_chipselect = 2,
|
||||
.activate_cs = db1200_spi_cs_en,
|
||||
};
|
||||
|
||||
static u64 spi_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
static struct platform_device db1200_spi_dev = {
|
||||
.dev = {
|
||||
.dma_mask = &spi_dmamask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
.platform_data = &db1200_spi_platdata,
|
||||
},
|
||||
.name = "au1550-spi",
|
||||
.id = 0, /* bus number */
|
||||
.num_resources = ARRAY_SIZE(au1200_psc0_res),
|
||||
.resource = au1200_psc0_res,
|
||||
};
|
||||
|
||||
static struct resource au1200_psc1_res[] = {
|
||||
[0] = {
|
||||
.start = AU1550_PSC1_PHYS_ADDR,
|
||||
.end = AU1550_PSC1_PHYS_ADDR + 0xfff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = AU1200_PSC1_INT,
|
||||
.end = AU1200_PSC1_INT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[2] = {
|
||||
.start = AU1200_DSCR_CMD0_PSC1_TX,
|
||||
.end = AU1200_DSCR_CMD0_PSC1_TX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[3] = {
|
||||
.start = AU1200_DSCR_CMD0_PSC1_RX,
|
||||
.end = AU1200_DSCR_CMD0_PSC1_RX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
/* AC97 or I2S device */
|
||||
static struct platform_device db1200_audio_dev = {
|
||||
/* name assigned later based on switch setting */
|
||||
.id = 1, /* PSC ID */
|
||||
.num_resources = ARRAY_SIZE(au1200_psc1_res),
|
||||
.resource = au1200_psc1_res,
|
||||
};
|
||||
|
||||
/* DB1200 ASoC card device */
|
||||
static struct platform_device db1200_sound_dev = {
|
||||
/* name assigned later based on switch setting */
|
||||
.id = 1, /* PSC ID */
|
||||
};
|
||||
|
||||
static struct platform_device db1200_stac_dev = {
|
||||
.name = "ac97-codec",
|
||||
.id = 1, /* on PSC1 */
|
||||
};
|
||||
|
||||
static struct platform_device db1200_audiodma_dev = {
|
||||
.name = "au1xpsc-pcm",
|
||||
.id = 1, /* PSC ID */
|
||||
};
|
||||
|
||||
static struct platform_device *db1200_devs[] __initdata = {
|
||||
NULL, /* PSC0, selected by S6.8 */
|
||||
&db1200_ide_dev,
|
||||
&db1200_mmc0_dev,
|
||||
&au1200_lcd_dev,
|
||||
&db1200_eth_dev,
|
||||
&db1200_nand_dev,
|
||||
&db1200_audiodma_dev,
|
||||
&db1200_audio_dev,
|
||||
&db1200_stac_dev,
|
||||
&db1200_sound_dev,
|
||||
};
|
||||
|
||||
static struct platform_device *pb1200_devs[] __initdata = {
|
||||
&pb1200_mmc1_dev,
|
||||
};
|
||||
|
||||
/* Some peripheral base addresses differ on the PB1200 */
|
||||
static int __init pb1200_res_fixup(void)
|
||||
{
|
||||
/* CPLD Revs earlier than 4 cause problems */
|
||||
if (BCSR_WHOAMI_CPLD(bcsr_read(BCSR_WHOAMI)) <= 3) {
|
||||
printk(KERN_ERR "WARNING!!!\n");
|
||||
printk(KERN_ERR "WARNING!!!\n");
|
||||
printk(KERN_ERR "PB1200 must be at CPLD rev 4. Please have\n");
|
||||
printk(KERN_ERR "the board updated to latest revisions.\n");
|
||||
printk(KERN_ERR "This software will not work reliably\n");
|
||||
printk(KERN_ERR "on anything older than CPLD rev 4.!\n");
|
||||
printk(KERN_ERR "WARNING!!!\n");
|
||||
printk(KERN_ERR "WARNING!!!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
db1200_nand_res[0].start = PB1200_NAND_PHYS_ADDR;
|
||||
db1200_nand_res[0].end = PB1200_NAND_PHYS_ADDR + 0xff;
|
||||
db1200_ide_res[0].start = PB1200_IDE_PHYS_ADDR;
|
||||
db1200_ide_res[0].end = PB1200_IDE_PHYS_ADDR + DB1200_IDE_PHYS_LEN - 1;
|
||||
db1200_eth_res[0].start = PB1200_ETH_PHYS_ADDR;
|
||||
db1200_eth_res[0].end = PB1200_ETH_PHYS_ADDR + 0xff;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init db1200_dev_setup(void)
|
||||
{
|
||||
unsigned long pfc;
|
||||
unsigned short sw;
|
||||
int swapped, bid;
|
||||
struct clk *c;
|
||||
|
||||
bid = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI));
|
||||
if ((bid == BCSR_WHOAMI_PB1200_DDR1) ||
|
||||
(bid == BCSR_WHOAMI_PB1200_DDR2)) {
|
||||
if (pb1200_res_fixup())
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* GPIO7 is low-level triggered CPLD cascade */
|
||||
irq_set_irq_type(AU1200_GPIO7_INT, IRQ_TYPE_LEVEL_LOW);
|
||||
bcsr_init_irq(DB1200_INT_BEGIN, DB1200_INT_END, AU1200_GPIO7_INT);
|
||||
|
||||
/* SMBus/SPI on PSC0, Audio on PSC1 */
|
||||
pfc = alchemy_rdsys(AU1000_SYS_PINFUNC);
|
||||
pfc &= ~(SYS_PINFUNC_P0A | SYS_PINFUNC_P0B);
|
||||
pfc &= ~(SYS_PINFUNC_P1A | SYS_PINFUNC_P1B | SYS_PINFUNC_FS3);
|
||||
pfc |= SYS_PINFUNC_P1C; /* SPI is configured later */
|
||||
alchemy_wrsys(pfc, AU1000_SYS_PINFUNC);
|
||||
|
||||
/* get 50MHz for I2C driver on PSC0 */
|
||||
c = clk_get(NULL, "psc0_intclk");
|
||||
if (!IS_ERR(c)) {
|
||||
pfc = clk_round_rate(c, 50000000);
|
||||
if ((pfc < 1) || (abs(50000000 - pfc) > 2500000))
|
||||
pr_warn("DB1200: cant get I2C close to 50MHz\n");
|
||||
else
|
||||
clk_set_rate(c, pfc);
|
||||
clk_prepare_enable(c);
|
||||
clk_put(c);
|
||||
}
|
||||
|
||||
/* insert/eject pairs: one of both is always screaming. To avoid
|
||||
* issues they must not be automatically enabled when initially
|
||||
* requested.
|
||||
*/
|
||||
irq_set_status_flags(DB1200_SD0_INSERT_INT, IRQ_NOAUTOEN);
|
||||
irq_set_status_flags(DB1200_SD0_EJECT_INT, IRQ_NOAUTOEN);
|
||||
irq_set_status_flags(DB1200_PC0_INSERT_INT, IRQ_NOAUTOEN);
|
||||
irq_set_status_flags(DB1200_PC0_EJECT_INT, IRQ_NOAUTOEN);
|
||||
irq_set_status_flags(DB1200_PC1_INSERT_INT, IRQ_NOAUTOEN);
|
||||
irq_set_status_flags(DB1200_PC1_EJECT_INT, IRQ_NOAUTOEN);
|
||||
|
||||
i2c_register_board_info(0, db1200_i2c_devs,
|
||||
ARRAY_SIZE(db1200_i2c_devs));
|
||||
spi_register_board_info(db1200_spi_devs,
|
||||
ARRAY_SIZE(db1200_i2c_devs));
|
||||
|
||||
/* SWITCHES: S6.8 I2C/SPI selector (OFF=I2C ON=SPI)
|
||||
* S6.7 AC97/I2S selector (OFF=AC97 ON=I2S)
|
||||
* or S12 on the PB1200.
|
||||
*/
|
||||
|
||||
/* NOTE: GPIO215 controls OTG VBUS supply. In SPI mode however
|
||||
* this pin is claimed by PSC0 (unused though, but pinmux doesn't
|
||||
* allow to free it without crippling the SPI interface).
|
||||
* As a result, in SPI mode, OTG simply won't work (PSC0 uses
|
||||
* it as an input pin which is pulled high on the boards).
|
||||
*/
|
||||
pfc = alchemy_rdsys(AU1000_SYS_PINFUNC) & ~SYS_PINFUNC_P0A;
|
||||
|
||||
/* switch off OTG VBUS supply */
|
||||
gpio_request(215, "otg-vbus");
|
||||
gpio_direction_output(215, 1);
|
||||
|
||||
printk(KERN_INFO "%s device configuration:\n", get_system_type());
|
||||
|
||||
sw = bcsr_read(BCSR_SWITCHES);
|
||||
if (sw & BCSR_SWITCHES_DIP_8) {
|
||||
db1200_devs[0] = &db1200_i2c_dev;
|
||||
bcsr_mod(BCSR_RESETS, BCSR_RESETS_PSC0MUX, 0);
|
||||
|
||||
pfc |= (2 << 17); /* GPIO2 block owns GPIO215 */
|
||||
|
||||
printk(KERN_INFO " S6.8 OFF: PSC0 mode I2C\n");
|
||||
printk(KERN_INFO " OTG port VBUS supply available!\n");
|
||||
} else {
|
||||
db1200_devs[0] = &db1200_spi_dev;
|
||||
bcsr_mod(BCSR_RESETS, 0, BCSR_RESETS_PSC0MUX);
|
||||
|
||||
pfc |= (1 << 17); /* PSC0 owns GPIO215 */
|
||||
|
||||
printk(KERN_INFO " S6.8 ON : PSC0 mode SPI\n");
|
||||
printk(KERN_INFO " OTG port VBUS supply disabled\n");
|
||||
}
|
||||
alchemy_wrsys(pfc, AU1000_SYS_PINFUNC);
|
||||
|
||||
/* Audio: DIP7 selects I2S(0)/AC97(1), but need I2C for I2S!
|
||||
* so: DIP7=1 || DIP8=0 => AC97, DIP7=0 && DIP8=1 => I2S
|
||||
*/
|
||||
sw &= BCSR_SWITCHES_DIP_8 | BCSR_SWITCHES_DIP_7;
|
||||
if (sw == BCSR_SWITCHES_DIP_8) {
|
||||
bcsr_mod(BCSR_RESETS, 0, BCSR_RESETS_PSC1MUX);
|
||||
db1200_audio_dev.name = "au1xpsc_i2s";
|
||||
db1200_sound_dev.name = "db1200-i2s";
|
||||
printk(KERN_INFO " S6.7 ON : PSC1 mode I2S\n");
|
||||
} else {
|
||||
bcsr_mod(BCSR_RESETS, BCSR_RESETS_PSC1MUX, 0);
|
||||
db1200_audio_dev.name = "au1xpsc_ac97";
|
||||
db1200_sound_dev.name = "db1200-ac97";
|
||||
printk(KERN_INFO " S6.7 OFF: PSC1 mode AC97\n");
|
||||
}
|
||||
|
||||
/* Audio PSC clock is supplied externally. (FIXME: platdata!!) */
|
||||
__raw_writel(PSC_SEL_CLK_SERCLK,
|
||||
(void __iomem *)KSEG1ADDR(AU1550_PSC1_PHYS_ADDR) + PSC_SEL_OFFSET);
|
||||
wmb();
|
||||
|
||||
db1x_register_pcmcia_socket(
|
||||
AU1000_PCMCIA_ATTR_PHYS_ADDR,
|
||||
AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
|
||||
AU1000_PCMCIA_MEM_PHYS_ADDR,
|
||||
AU1000_PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1,
|
||||
AU1000_PCMCIA_IO_PHYS_ADDR,
|
||||
AU1000_PCMCIA_IO_PHYS_ADDR + 0x000010000 - 1,
|
||||
DB1200_PC0_INT, DB1200_PC0_INSERT_INT,
|
||||
/*DB1200_PC0_STSCHG_INT*/0, DB1200_PC0_EJECT_INT, 0);
|
||||
|
||||
db1x_register_pcmcia_socket(
|
||||
AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004000000,
|
||||
AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004400000 - 1,
|
||||
AU1000_PCMCIA_MEM_PHYS_ADDR + 0x004000000,
|
||||
AU1000_PCMCIA_MEM_PHYS_ADDR + 0x004400000 - 1,
|
||||
AU1000_PCMCIA_IO_PHYS_ADDR + 0x004000000,
|
||||
AU1000_PCMCIA_IO_PHYS_ADDR + 0x004010000 - 1,
|
||||
DB1200_PC1_INT, DB1200_PC1_INSERT_INT,
|
||||
/*DB1200_PC1_STSCHG_INT*/0, DB1200_PC1_EJECT_INT, 1);
|
||||
|
||||
swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1200_SWAPBOOT;
|
||||
db1x_register_norflash(64 << 20, 2, swapped);
|
||||
|
||||
platform_add_devices(db1200_devs, ARRAY_SIZE(db1200_devs));
|
||||
|
||||
/* PB1200 is a DB1200 with a 2nd MMC and Camera connector */
|
||||
if ((bid == BCSR_WHOAMI_PB1200_DDR1) ||
|
||||
(bid == BCSR_WHOAMI_PB1200_DDR2))
|
||||
platform_add_devices(pb1200_devs, ARRAY_SIZE(pb1200_devs));
|
||||
|
||||
return 0;
|
||||
}
|
866
arch/mips/alchemy/devboards/db1300.c
Normal file
866
arch/mips/alchemy/devboards/db1300.c
Normal file
|
@ -0,0 +1,866 @@
|
|||
/*
|
||||
* DBAu1300 init and platform device setup.
|
||||
*
|
||||
* (c) 2009 Manuel Lauss <manuel.lauss@googlemail.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio_keys.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h> /* KEY_* codes */
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/ata_platform.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/smsc911x.h>
|
||||
#include <linux/wm97xx.h>
|
||||
|
||||
#include <asm/mach-au1x00/au1000.h>
|
||||
#include <asm/mach-au1x00/au1100_mmc.h>
|
||||
#include <asm/mach-au1x00/au1200fb.h>
|
||||
#include <asm/mach-au1x00/au1xxx_dbdma.h>
|
||||
#include <asm/mach-au1x00/au1xxx_psc.h>
|
||||
#include <asm/mach-db1x00/bcsr.h>
|
||||
#include <asm/mach-au1x00/prom.h>
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
/* FPGA (external mux) interrupt sources */
|
||||
#define DB1300_FIRST_INT (ALCHEMY_GPIC_INT_LAST + 1)
|
||||
#define DB1300_IDE_INT (DB1300_FIRST_INT + 0)
|
||||
#define DB1300_ETH_INT (DB1300_FIRST_INT + 1)
|
||||
#define DB1300_CF_INT (DB1300_FIRST_INT + 2)
|
||||
#define DB1300_VIDEO_INT (DB1300_FIRST_INT + 4)
|
||||
#define DB1300_HDMI_INT (DB1300_FIRST_INT + 5)
|
||||
#define DB1300_DC_INT (DB1300_FIRST_INT + 6)
|
||||
#define DB1300_FLASH_INT (DB1300_FIRST_INT + 7)
|
||||
#define DB1300_CF_INSERT_INT (DB1300_FIRST_INT + 8)
|
||||
#define DB1300_CF_EJECT_INT (DB1300_FIRST_INT + 9)
|
||||
#define DB1300_AC97_INT (DB1300_FIRST_INT + 10)
|
||||
#define DB1300_AC97_PEN_INT (DB1300_FIRST_INT + 11)
|
||||
#define DB1300_SD1_INSERT_INT (DB1300_FIRST_INT + 12)
|
||||
#define DB1300_SD1_EJECT_INT (DB1300_FIRST_INT + 13)
|
||||
#define DB1300_OTG_VBUS_OC_INT (DB1300_FIRST_INT + 14)
|
||||
#define DB1300_HOST_VBUS_OC_INT (DB1300_FIRST_INT + 15)
|
||||
#define DB1300_LAST_INT (DB1300_FIRST_INT + 15)
|
||||
|
||||
/* SMSC9210 CS */
|
||||
#define DB1300_ETH_PHYS_ADDR 0x19000000
|
||||
#define DB1300_ETH_PHYS_END 0x197fffff
|
||||
|
||||
/* ATA CS */
|
||||
#define DB1300_IDE_PHYS_ADDR 0x18800000
|
||||
#define DB1300_IDE_REG_SHIFT 5
|
||||
#define DB1300_IDE_PHYS_LEN (16 << DB1300_IDE_REG_SHIFT)
|
||||
|
||||
/* NAND CS */
|
||||
#define DB1300_NAND_PHYS_ADDR 0x20000000
|
||||
#define DB1300_NAND_PHYS_END 0x20000fff
|
||||
|
||||
|
||||
static struct i2c_board_info db1300_i2c_devs[] __initdata = {
|
||||
{ I2C_BOARD_INFO("wm8731", 0x1b), }, /* I2S audio codec */
|
||||
{ I2C_BOARD_INFO("ne1619", 0x2d), }, /* adm1025-compat hwmon */
|
||||
};
|
||||
|
||||
/* multifunction pins to assign to GPIO controller */
|
||||
static int db1300_gpio_pins[] __initdata = {
|
||||
AU1300_PIN_LCDPWM0, AU1300_PIN_PSC2SYNC1, AU1300_PIN_WAKE1,
|
||||
AU1300_PIN_WAKE2, AU1300_PIN_WAKE3, AU1300_PIN_FG3AUX,
|
||||
AU1300_PIN_EXTCLK1,
|
||||
-1, /* terminator */
|
||||
};
|
||||
|
||||
/* multifunction pins to assign to device functions */
|
||||
static int db1300_dev_pins[] __initdata = {
|
||||
/* wake-from-str pins 0-3 */
|
||||
AU1300_PIN_WAKE0,
|
||||
/* external clock sources for PSC0 */
|
||||
AU1300_PIN_EXTCLK0,
|
||||
/* 8bit MMC interface on SD0: 6-9 */
|
||||
AU1300_PIN_SD0DAT4, AU1300_PIN_SD0DAT5, AU1300_PIN_SD0DAT6,
|
||||
AU1300_PIN_SD0DAT7,
|
||||
/* UART1 pins: 11-18 */
|
||||
AU1300_PIN_U1RI, AU1300_PIN_U1DCD, AU1300_PIN_U1DSR,
|
||||
AU1300_PIN_U1CTS, AU1300_PIN_U1RTS, AU1300_PIN_U1DTR,
|
||||
AU1300_PIN_U1RX, AU1300_PIN_U1TX,
|
||||
/* UART0 pins: 19-24 */
|
||||
AU1300_PIN_U0RI, AU1300_PIN_U0DCD, AU1300_PIN_U0DSR,
|
||||
AU1300_PIN_U0CTS, AU1300_PIN_U0RTS, AU1300_PIN_U0DTR,
|
||||
/* UART2: 25-26 */
|
||||
AU1300_PIN_U2RX, AU1300_PIN_U2TX,
|
||||
/* UART3: 27-28 */
|
||||
AU1300_PIN_U3RX, AU1300_PIN_U3TX,
|
||||
/* LCD controller PWMs, ext pixclock: 30-31 */
|
||||
AU1300_PIN_LCDPWM1, AU1300_PIN_LCDCLKIN,
|
||||
/* SD1 interface: 32-37 */
|
||||
AU1300_PIN_SD1DAT0, AU1300_PIN_SD1DAT1, AU1300_PIN_SD1DAT2,
|
||||
AU1300_PIN_SD1DAT3, AU1300_PIN_SD1CMD, AU1300_PIN_SD1CLK,
|
||||
/* SD2 interface: 38-43 */
|
||||
AU1300_PIN_SD2DAT0, AU1300_PIN_SD2DAT1, AU1300_PIN_SD2DAT2,
|
||||
AU1300_PIN_SD2DAT3, AU1300_PIN_SD2CMD, AU1300_PIN_SD2CLK,
|
||||
/* PSC0/1 clocks: 44-45 */
|
||||
AU1300_PIN_PSC0CLK, AU1300_PIN_PSC1CLK,
|
||||
/* PSCs: 46-49/50-53/54-57/58-61 */
|
||||
AU1300_PIN_PSC0SYNC0, AU1300_PIN_PSC0SYNC1, AU1300_PIN_PSC0D0,
|
||||
AU1300_PIN_PSC0D1,
|
||||
AU1300_PIN_PSC1SYNC0, AU1300_PIN_PSC1SYNC1, AU1300_PIN_PSC1D0,
|
||||
AU1300_PIN_PSC1D1,
|
||||
AU1300_PIN_PSC2SYNC0, AU1300_PIN_PSC2D0,
|
||||
AU1300_PIN_PSC2D1,
|
||||
AU1300_PIN_PSC3SYNC0, AU1300_PIN_PSC3SYNC1, AU1300_PIN_PSC3D0,
|
||||
AU1300_PIN_PSC3D1,
|
||||
/* PCMCIA interface: 62-70 */
|
||||
AU1300_PIN_PCE2, AU1300_PIN_PCE1, AU1300_PIN_PIOS16,
|
||||
AU1300_PIN_PIOR, AU1300_PIN_PWE, AU1300_PIN_PWAIT,
|
||||
AU1300_PIN_PREG, AU1300_PIN_POE, AU1300_PIN_PIOW,
|
||||
/* camera interface H/V sync inputs: 71-72 */
|
||||
AU1300_PIN_CIMLS, AU1300_PIN_CIMFS,
|
||||
/* PSC2/3 clocks: 73-74 */
|
||||
AU1300_PIN_PSC2CLK, AU1300_PIN_PSC3CLK,
|
||||
-1, /* terminator */
|
||||
};
|
||||
|
||||
static void __init db1300_gpio_config(void)
|
||||
{
|
||||
int *i;
|
||||
|
||||
i = &db1300_dev_pins[0];
|
||||
while (*i != -1)
|
||||
au1300_pinfunc_to_dev(*i++);
|
||||
|
||||
i = &db1300_gpio_pins[0];
|
||||
while (*i != -1)
|
||||
au1300_gpio_direction_input(*i++);/* implies pin_to_gpio */
|
||||
|
||||
au1300_set_dbdma_gpio(1, AU1300_PIN_FG3AUX);
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static void au1300_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
unsigned long ioaddr = (unsigned long)this->IO_ADDR_W;
|
||||
|
||||
ioaddr &= 0xffffff00;
|
||||
|
||||
if (ctrl & NAND_CLE) {
|
||||
ioaddr += MEM_STNAND_CMD;
|
||||
} else if (ctrl & NAND_ALE) {
|
||||
ioaddr += MEM_STNAND_ADDR;
|
||||
} else {
|
||||
/* assume we want to r/w real data by default */
|
||||
ioaddr += MEM_STNAND_DATA;
|
||||
}
|
||||
this->IO_ADDR_R = this->IO_ADDR_W = (void __iomem *)ioaddr;
|
||||
if (cmd != NAND_CMD_NONE) {
|
||||
__raw_writeb(cmd, this->IO_ADDR_W);
|
||||
wmb();
|
||||
}
|
||||
}
|
||||
|
||||
static int au1300_nand_device_ready(struct mtd_info *mtd)
|
||||
{
|
||||
return alchemy_rdsmem(AU1000_MEM_STSTAT) & 1;
|
||||
}
|
||||
|
||||
static struct mtd_partition db1300_nand_parts[] = {
|
||||
{
|
||||
.name = "NAND FS 0",
|
||||
.offset = 0,
|
||||
.size = 8 * 1024 * 1024,
|
||||
},
|
||||
{
|
||||
.name = "NAND FS 1",
|
||||
.offset = MTDPART_OFS_APPEND,
|
||||
.size = MTDPART_SIZ_FULL
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_nand_data db1300_nand_platdata = {
|
||||
.chip = {
|
||||
.nr_chips = 1,
|
||||
.chip_offset = 0,
|
||||
.nr_partitions = ARRAY_SIZE(db1300_nand_parts),
|
||||
.partitions = db1300_nand_parts,
|
||||
.chip_delay = 20,
|
||||
},
|
||||
.ctrl = {
|
||||
.dev_ready = au1300_nand_device_ready,
|
||||
.cmd_ctrl = au1300_nand_cmd_ctrl,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource db1300_nand_res[] = {
|
||||
[0] = {
|
||||
.start = DB1300_NAND_PHYS_ADDR,
|
||||
.end = DB1300_NAND_PHYS_ADDR + 0xff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device db1300_nand_dev = {
|
||||
.name = "gen_nand",
|
||||
.num_resources = ARRAY_SIZE(db1300_nand_res),
|
||||
.resource = db1300_nand_res,
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.platform_data = &db1300_nand_platdata,
|
||||
}
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static struct resource db1300_eth_res[] = {
|
||||
[0] = {
|
||||
.start = DB1300_ETH_PHYS_ADDR,
|
||||
.end = DB1300_ETH_PHYS_END,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = DB1300_ETH_INT,
|
||||
.end = DB1300_ETH_INT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct smsc911x_platform_config db1300_eth_config = {
|
||||
.phy_interface = PHY_INTERFACE_MODE_MII,
|
||||
.irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
|
||||
.irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL,
|
||||
.flags = SMSC911X_USE_32BIT,
|
||||
};
|
||||
|
||||
static struct platform_device db1300_eth_dev = {
|
||||
.name = "smsc911x",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(db1300_eth_res),
|
||||
.resource = db1300_eth_res,
|
||||
.dev = {
|
||||
.platform_data = &db1300_eth_config,
|
||||
},
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static struct resource au1300_psc1_res[] = {
|
||||
[0] = {
|
||||
.start = AU1300_PSC1_PHYS_ADDR,
|
||||
.end = AU1300_PSC1_PHYS_ADDR + 0x0fff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = AU1300_PSC1_INT,
|
||||
.end = AU1300_PSC1_INT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[2] = {
|
||||
.start = AU1300_DSCR_CMD0_PSC1_TX,
|
||||
.end = AU1300_DSCR_CMD0_PSC1_TX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[3] = {
|
||||
.start = AU1300_DSCR_CMD0_PSC1_RX,
|
||||
.end = AU1300_DSCR_CMD0_PSC1_RX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device db1300_ac97_dev = {
|
||||
.name = "au1xpsc_ac97",
|
||||
.id = 1, /* PSC ID. match with AC97 codec ID! */
|
||||
.num_resources = ARRAY_SIZE(au1300_psc1_res),
|
||||
.resource = au1300_psc1_res,
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static struct resource au1300_psc2_res[] = {
|
||||
[0] = {
|
||||
.start = AU1300_PSC2_PHYS_ADDR,
|
||||
.end = AU1300_PSC2_PHYS_ADDR + 0x0fff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = AU1300_PSC2_INT,
|
||||
.end = AU1300_PSC2_INT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[2] = {
|
||||
.start = AU1300_DSCR_CMD0_PSC2_TX,
|
||||
.end = AU1300_DSCR_CMD0_PSC2_TX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[3] = {
|
||||
.start = AU1300_DSCR_CMD0_PSC2_RX,
|
||||
.end = AU1300_DSCR_CMD0_PSC2_RX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device db1300_i2s_dev = {
|
||||
.name = "au1xpsc_i2s",
|
||||
.id = 2, /* PSC ID */
|
||||
.num_resources = ARRAY_SIZE(au1300_psc2_res),
|
||||
.resource = au1300_psc2_res,
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static struct resource au1300_psc3_res[] = {
|
||||
[0] = {
|
||||
.start = AU1300_PSC3_PHYS_ADDR,
|
||||
.end = AU1300_PSC3_PHYS_ADDR + 0x0fff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = AU1300_PSC3_INT,
|
||||
.end = AU1300_PSC3_INT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[2] = {
|
||||
.start = AU1300_DSCR_CMD0_PSC3_TX,
|
||||
.end = AU1300_DSCR_CMD0_PSC3_TX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[3] = {
|
||||
.start = AU1300_DSCR_CMD0_PSC3_RX,
|
||||
.end = AU1300_DSCR_CMD0_PSC3_RX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device db1300_i2c_dev = {
|
||||
.name = "au1xpsc_smbus",
|
||||
.id = 0, /* bus number */
|
||||
.num_resources = ARRAY_SIZE(au1300_psc3_res),
|
||||
.resource = au1300_psc3_res,
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/* proper key assignments when facing the LCD panel. For key assignments
|
||||
* according to the schematics swap up with down and left with right.
|
||||
* I chose to use it to emulate the arrow keys of a keyboard.
|
||||
*/
|
||||
static struct gpio_keys_button db1300_5waysw_arrowkeys[] = {
|
||||
{
|
||||
.code = KEY_DOWN,
|
||||
.gpio = AU1300_PIN_LCDPWM0,
|
||||
.type = EV_KEY,
|
||||
.debounce_interval = 1,
|
||||
.active_low = 1,
|
||||
.desc = "5waysw-down",
|
||||
},
|
||||
{
|
||||
.code = KEY_UP,
|
||||
.gpio = AU1300_PIN_PSC2SYNC1,
|
||||
.type = EV_KEY,
|
||||
.debounce_interval = 1,
|
||||
.active_low = 1,
|
||||
.desc = "5waysw-up",
|
||||
},
|
||||
{
|
||||
.code = KEY_RIGHT,
|
||||
.gpio = AU1300_PIN_WAKE3,
|
||||
.type = EV_KEY,
|
||||
.debounce_interval = 1,
|
||||
.active_low = 1,
|
||||
.desc = "5waysw-right",
|
||||
},
|
||||
{
|
||||
.code = KEY_LEFT,
|
||||
.gpio = AU1300_PIN_WAKE2,
|
||||
.type = EV_KEY,
|
||||
.debounce_interval = 1,
|
||||
.active_low = 1,
|
||||
.desc = "5waysw-left",
|
||||
},
|
||||
{
|
||||
.code = KEY_ENTER,
|
||||
.gpio = AU1300_PIN_WAKE1,
|
||||
.type = EV_KEY,
|
||||
.debounce_interval = 1,
|
||||
.active_low = 1,
|
||||
.desc = "5waysw-push",
|
||||
},
|
||||
};
|
||||
|
||||
static struct gpio_keys_platform_data db1300_5waysw_data = {
|
||||
.buttons = db1300_5waysw_arrowkeys,
|
||||
.nbuttons = ARRAY_SIZE(db1300_5waysw_arrowkeys),
|
||||
.rep = 1,
|
||||
.name = "db1300-5wayswitch",
|
||||
};
|
||||
|
||||
static struct platform_device db1300_5waysw_dev = {
|
||||
.name = "gpio-keys",
|
||||
.dev = {
|
||||
.platform_data = &db1300_5waysw_data,
|
||||
},
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static struct pata_platform_info db1300_ide_info = {
|
||||
.ioport_shift = DB1300_IDE_REG_SHIFT,
|
||||
};
|
||||
|
||||
#define IDE_ALT_START (14 << DB1300_IDE_REG_SHIFT)
|
||||
static struct resource db1300_ide_res[] = {
|
||||
[0] = {
|
||||
.start = DB1300_IDE_PHYS_ADDR,
|
||||
.end = DB1300_IDE_PHYS_ADDR + IDE_ALT_START - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = DB1300_IDE_PHYS_ADDR + IDE_ALT_START,
|
||||
.end = DB1300_IDE_PHYS_ADDR + DB1300_IDE_PHYS_LEN - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[2] = {
|
||||
.start = DB1300_IDE_INT,
|
||||
.end = DB1300_IDE_INT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device db1300_ide_dev = {
|
||||
.dev = {
|
||||
.platform_data = &db1300_ide_info,
|
||||
},
|
||||
.name = "pata_platform",
|
||||
.resource = db1300_ide_res,
|
||||
.num_resources = ARRAY_SIZE(db1300_ide_res),
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static irqreturn_t db1300_mmc_cd(int irq, void *ptr)
|
||||
{
|
||||
void(*mmc_cd)(struct mmc_host *, unsigned long);
|
||||
|
||||
/* disable the one currently screaming. No other way to shut it up */
|
||||
if (irq == DB1300_SD1_INSERT_INT) {
|
||||
disable_irq_nosync(DB1300_SD1_INSERT_INT);
|
||||
enable_irq(DB1300_SD1_EJECT_INT);
|
||||
} else {
|
||||
disable_irq_nosync(DB1300_SD1_EJECT_INT);
|
||||
enable_irq(DB1300_SD1_INSERT_INT);
|
||||
}
|
||||
|
||||
/* link against CONFIG_MMC=m. We can only be called once MMC core has
|
||||
* initialized the controller, so symbol_get() should always succeed.
|
||||
*/
|
||||
mmc_cd = symbol_get(mmc_detect_change);
|
||||
mmc_cd(ptr, msecs_to_jiffies(500));
|
||||
symbol_put(mmc_detect_change);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int db1300_mmc_card_readonly(void *mmc_host)
|
||||
{
|
||||
/* it uses SD1 interface, but the DB1200's SD0 bit in the CPLD */
|
||||
return bcsr_read(BCSR_STATUS) & BCSR_STATUS_SD0WP;
|
||||
}
|
||||
|
||||
static int db1300_mmc_card_inserted(void *mmc_host)
|
||||
{
|
||||
return bcsr_read(BCSR_SIGSTAT) & (1 << 12); /* insertion irq signal */
|
||||
}
|
||||
|
||||
static int db1300_mmc_cd_setup(void *mmc_host, int en)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (en) {
|
||||
ret = request_irq(DB1300_SD1_INSERT_INT, db1300_mmc_cd, 0,
|
||||
"sd_insert", mmc_host);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = request_irq(DB1300_SD1_EJECT_INT, db1300_mmc_cd, 0,
|
||||
"sd_eject", mmc_host);
|
||||
if (ret) {
|
||||
free_irq(DB1300_SD1_INSERT_INT, mmc_host);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (db1300_mmc_card_inserted(mmc_host))
|
||||
enable_irq(DB1300_SD1_EJECT_INT);
|
||||
else
|
||||
enable_irq(DB1300_SD1_INSERT_INT);
|
||||
|
||||
} else {
|
||||
free_irq(DB1300_SD1_INSERT_INT, mmc_host);
|
||||
free_irq(DB1300_SD1_EJECT_INT, mmc_host);
|
||||
}
|
||||
ret = 0;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void db1300_mmcled_set(struct led_classdev *led,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
if (brightness != LED_OFF)
|
||||
bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED0, 0);
|
||||
else
|
||||
bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED0);
|
||||
}
|
||||
|
||||
static struct led_classdev db1300_mmc_led = {
|
||||
.brightness_set = db1300_mmcled_set,
|
||||
};
|
||||
|
||||
struct au1xmmc_platform_data db1300_sd1_platdata = {
|
||||
.cd_setup = db1300_mmc_cd_setup,
|
||||
.card_inserted = db1300_mmc_card_inserted,
|
||||
.card_readonly = db1300_mmc_card_readonly,
|
||||
.led = &db1300_mmc_led,
|
||||
};
|
||||
|
||||
static struct resource au1300_sd1_res[] = {
|
||||
[0] = {
|
||||
.start = AU1300_SD1_PHYS_ADDR,
|
||||
.end = AU1300_SD1_PHYS_ADDR,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = AU1300_SD1_INT,
|
||||
.end = AU1300_SD1_INT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[2] = {
|
||||
.start = AU1300_DSCR_CMD0_SDMS_TX1,
|
||||
.end = AU1300_DSCR_CMD0_SDMS_TX1,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[3] = {
|
||||
.start = AU1300_DSCR_CMD0_SDMS_RX1,
|
||||
.end = AU1300_DSCR_CMD0_SDMS_RX1,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device db1300_sd1_dev = {
|
||||
.dev = {
|
||||
.platform_data = &db1300_sd1_platdata,
|
||||
},
|
||||
.name = "au1xxx-mmc",
|
||||
.id = 1,
|
||||
.resource = au1300_sd1_res,
|
||||
.num_resources = ARRAY_SIZE(au1300_sd1_res),
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static int db1300_movinand_inserted(void *mmc_host)
|
||||
{
|
||||
return 0; /* disable for now, it doesn't work yet */
|
||||
}
|
||||
|
||||
static int db1300_movinand_readonly(void *mmc_host)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void db1300_movinand_led_set(struct led_classdev *led,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
if (brightness != LED_OFF)
|
||||
bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED1, 0);
|
||||
else
|
||||
bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED1);
|
||||
}
|
||||
|
||||
static struct led_classdev db1300_movinand_led = {
|
||||
.brightness_set = db1300_movinand_led_set,
|
||||
};
|
||||
|
||||
struct au1xmmc_platform_data db1300_sd0_platdata = {
|
||||
.card_inserted = db1300_movinand_inserted,
|
||||
.card_readonly = db1300_movinand_readonly,
|
||||
.led = &db1300_movinand_led,
|
||||
.mask_host_caps = MMC_CAP_NEEDS_POLL,
|
||||
};
|
||||
|
||||
static struct resource au1300_sd0_res[] = {
|
||||
[0] = {
|
||||
.start = AU1100_SD0_PHYS_ADDR,
|
||||
.end = AU1100_SD0_PHYS_ADDR,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = AU1300_SD0_INT,
|
||||
.end = AU1300_SD0_INT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[2] = {
|
||||
.start = AU1300_DSCR_CMD0_SDMS_TX0,
|
||||
.end = AU1300_DSCR_CMD0_SDMS_TX0,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[3] = {
|
||||
.start = AU1300_DSCR_CMD0_SDMS_RX0,
|
||||
.end = AU1300_DSCR_CMD0_SDMS_RX0,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device db1300_sd0_dev = {
|
||||
.dev = {
|
||||
.platform_data = &db1300_sd0_platdata,
|
||||
},
|
||||
.name = "au1xxx-mmc",
|
||||
.id = 0,
|
||||
.resource = au1300_sd0_res,
|
||||
.num_resources = ARRAY_SIZE(au1300_sd0_res),
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static struct platform_device db1300_wm9715_dev = {
|
||||
.name = "wm9712-codec",
|
||||
.id = 1, /* ID of PSC for AC97 audio, see asoc glue! */
|
||||
};
|
||||
|
||||
static struct platform_device db1300_ac97dma_dev = {
|
||||
.name = "au1xpsc-pcm",
|
||||
.id = 1, /* PSC ID */
|
||||
};
|
||||
|
||||
static struct platform_device db1300_i2sdma_dev = {
|
||||
.name = "au1xpsc-pcm",
|
||||
.id = 2, /* PSC ID */
|
||||
};
|
||||
|
||||
static struct platform_device db1300_sndac97_dev = {
|
||||
.name = "db1300-ac97",
|
||||
};
|
||||
|
||||
static struct platform_device db1300_sndi2s_dev = {
|
||||
.name = "db1300-i2s",
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static int db1300fb_panel_index(void)
|
||||
{
|
||||
return 9; /* DB1300_800x480 */
|
||||
}
|
||||
|
||||
static int db1300fb_panel_init(void)
|
||||
{
|
||||
/* Apply power (Vee/Vdd logic is inverted on Panel DB1300_800x480) */
|
||||
bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD,
|
||||
BCSR_BOARD_LCDBL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int db1300fb_panel_shutdown(void)
|
||||
{
|
||||
/* Remove power (Vee/Vdd logic is inverted on Panel DB1300_800x480) */
|
||||
bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDBL,
|
||||
BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct au1200fb_platdata db1300fb_pd = {
|
||||
.panel_index = db1300fb_panel_index,
|
||||
.panel_init = db1300fb_panel_init,
|
||||
.panel_shutdown = db1300fb_panel_shutdown,
|
||||
};
|
||||
|
||||
static struct resource au1300_lcd_res[] = {
|
||||
[0] = {
|
||||
.start = AU1200_LCD_PHYS_ADDR,
|
||||
.end = AU1200_LCD_PHYS_ADDR + 0x800 - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = AU1300_LCD_INT,
|
||||
.end = AU1300_LCD_INT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
}
|
||||
};
|
||||
|
||||
static u64 au1300_lcd_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
static struct platform_device db1300_lcd_dev = {
|
||||
.name = "au1200-lcd",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.dma_mask = &au1300_lcd_dmamask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
.platform_data = &db1300fb_pd,
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(au1300_lcd_res),
|
||||
.resource = au1300_lcd_res,
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static void db1300_wm97xx_irqen(struct wm97xx *wm, int enable)
|
||||
{
|
||||
if (enable)
|
||||
enable_irq(DB1300_AC97_PEN_INT);
|
||||
else
|
||||
disable_irq_nosync(DB1300_AC97_PEN_INT);
|
||||
}
|
||||
|
||||
static struct wm97xx_mach_ops db1300_wm97xx_ops = {
|
||||
.irq_enable = db1300_wm97xx_irqen,
|
||||
.irq_gpio = WM97XX_GPIO_3,
|
||||
};
|
||||
|
||||
static int db1300_wm97xx_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct wm97xx *wm = platform_get_drvdata(pdev);
|
||||
|
||||
/* external pendown indicator */
|
||||
wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN,
|
||||
WM97XX_GPIO_POL_LOW, WM97XX_GPIO_STICKY,
|
||||
WM97XX_GPIO_WAKE);
|
||||
|
||||
/* internal "virtual" pendown gpio */
|
||||
wm97xx_config_gpio(wm, WM97XX_GPIO_3, WM97XX_GPIO_OUT,
|
||||
WM97XX_GPIO_POL_LOW, WM97XX_GPIO_NOTSTICKY,
|
||||
WM97XX_GPIO_NOWAKE);
|
||||
|
||||
wm->pen_irq = DB1300_AC97_PEN_INT;
|
||||
|
||||
return wm97xx_register_mach_ops(wm, &db1300_wm97xx_ops);
|
||||
}
|
||||
|
||||
static struct platform_driver db1300_wm97xx_driver = {
|
||||
.driver.name = "wm97xx-touch",
|
||||
.driver.owner = THIS_MODULE,
|
||||
.probe = db1300_wm97xx_probe,
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static struct platform_device *db1300_dev[] __initdata = {
|
||||
&db1300_eth_dev,
|
||||
&db1300_i2c_dev,
|
||||
&db1300_5waysw_dev,
|
||||
&db1300_nand_dev,
|
||||
&db1300_ide_dev,
|
||||
&db1300_sd0_dev,
|
||||
&db1300_sd1_dev,
|
||||
&db1300_lcd_dev,
|
||||
&db1300_ac97_dev,
|
||||
&db1300_i2s_dev,
|
||||
&db1300_wm9715_dev,
|
||||
&db1300_ac97dma_dev,
|
||||
&db1300_i2sdma_dev,
|
||||
&db1300_sndac97_dev,
|
||||
&db1300_sndi2s_dev,
|
||||
};
|
||||
|
||||
int __init db1300_dev_setup(void)
|
||||
{
|
||||
int swapped, cpldirq;
|
||||
struct clk *c;
|
||||
|
||||
/* setup CPLD IRQ muxer */
|
||||
cpldirq = au1300_gpio_to_irq(AU1300_PIN_EXTCLK1);
|
||||
irq_set_irq_type(cpldirq, IRQ_TYPE_LEVEL_HIGH);
|
||||
bcsr_init_irq(DB1300_FIRST_INT, DB1300_LAST_INT, cpldirq);
|
||||
|
||||
/* insert/eject IRQs: one always triggers so don't enable them
|
||||
* when doing request_irq() on them. DB1200 has this bug too.
|
||||
*/
|
||||
irq_set_status_flags(DB1300_SD1_INSERT_INT, IRQ_NOAUTOEN);
|
||||
irq_set_status_flags(DB1300_SD1_EJECT_INT, IRQ_NOAUTOEN);
|
||||
irq_set_status_flags(DB1300_CF_INSERT_INT, IRQ_NOAUTOEN);
|
||||
irq_set_status_flags(DB1300_CF_EJECT_INT, IRQ_NOAUTOEN);
|
||||
|
||||
/*
|
||||
* setup board
|
||||
*/
|
||||
prom_get_ethernet_addr(&db1300_eth_config.mac[0]);
|
||||
|
||||
i2c_register_board_info(0, db1300_i2c_devs,
|
||||
ARRAY_SIZE(db1300_i2c_devs));
|
||||
|
||||
if (platform_driver_register(&db1300_wm97xx_driver))
|
||||
pr_warn("DB1300: failed to init touch pen irq support!\n");
|
||||
|
||||
/* Audio PSC clock is supplied by codecs (PSC1, 2) */
|
||||
__raw_writel(PSC_SEL_CLK_SERCLK,
|
||||
(void __iomem *)KSEG1ADDR(AU1300_PSC1_PHYS_ADDR) + PSC_SEL_OFFSET);
|
||||
wmb();
|
||||
__raw_writel(PSC_SEL_CLK_SERCLK,
|
||||
(void __iomem *)KSEG1ADDR(AU1300_PSC2_PHYS_ADDR) + PSC_SEL_OFFSET);
|
||||
wmb();
|
||||
/* I2C driver wants 50MHz, get as close as possible */
|
||||
c = clk_get(NULL, "psc3_intclk");
|
||||
if (!IS_ERR(c)) {
|
||||
clk_set_rate(c, 50000000);
|
||||
clk_prepare_enable(c);
|
||||
clk_put(c);
|
||||
}
|
||||
__raw_writel(PSC_SEL_CLK_INTCLK,
|
||||
(void __iomem *)KSEG1ADDR(AU1300_PSC3_PHYS_ADDR) + PSC_SEL_OFFSET);
|
||||
wmb();
|
||||
|
||||
/* enable power to USB ports */
|
||||
bcsr_mod(BCSR_RESETS, 0, BCSR_RESETS_USBHPWR | BCSR_RESETS_OTGPWR);
|
||||
|
||||
/* although it is socket #0, it uses the CPLD bits which previous boards
|
||||
* have used for socket #1.
|
||||
*/
|
||||
db1x_register_pcmcia_socket(
|
||||
AU1000_PCMCIA_ATTR_PHYS_ADDR,
|
||||
AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x00400000 - 1,
|
||||
AU1000_PCMCIA_MEM_PHYS_ADDR,
|
||||
AU1000_PCMCIA_MEM_PHYS_ADDR + 0x00400000 - 1,
|
||||
AU1000_PCMCIA_IO_PHYS_ADDR,
|
||||
AU1000_PCMCIA_IO_PHYS_ADDR + 0x00010000 - 1,
|
||||
DB1300_CF_INT, DB1300_CF_INSERT_INT, 0, DB1300_CF_EJECT_INT, 1);
|
||||
|
||||
swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1200_SWAPBOOT;
|
||||
db1x_register_norflash(64 << 20, 2, swapped);
|
||||
|
||||
return platform_add_devices(db1300_dev, ARRAY_SIZE(db1300_dev));
|
||||
}
|
||||
|
||||
|
||||
int __init db1300_board_setup(void)
|
||||
{
|
||||
unsigned short whoami;
|
||||
|
||||
bcsr_init(DB1300_BCSR_PHYS_ADDR,
|
||||
DB1300_BCSR_PHYS_ADDR + DB1300_BCSR_HEXLED_OFS);
|
||||
|
||||
whoami = bcsr_read(BCSR_WHOAMI);
|
||||
if (BCSR_WHOAMI_BOARD(whoami) != BCSR_WHOAMI_DB1300)
|
||||
return -ENODEV;
|
||||
|
||||
db1300_gpio_config();
|
||||
|
||||
printk(KERN_INFO "NetLogic DBAu1300 Development Platform.\n\t"
|
||||
"BoardID %d CPLD Rev %d DaughtercardID %d\n",
|
||||
BCSR_WHOAMI_BOARD(whoami), BCSR_WHOAMI_CPLD(whoami),
|
||||
BCSR_WHOAMI_DCID(whoami));
|
||||
|
||||
/* enable UARTs, YAMON only enables #2 */
|
||||
alchemy_uart_enable(AU1300_UART0_PHYS_ADDR);
|
||||
alchemy_uart_enable(AU1300_UART1_PHYS_ADDR);
|
||||
alchemy_uart_enable(AU1300_UART3_PHYS_ADDR);
|
||||
|
||||
return 0;
|
||||
}
|
619
arch/mips/alchemy/devboards/db1550.c
Normal file
619
arch/mips/alchemy/devboards/db1550.c
Normal file
|
@ -0,0 +1,619 @@
|
|||
/*
|
||||
* Alchemy Db1550/Pb1550 board support
|
||||
*
|
||||
* (c) 2011 Manuel Lauss <manuel.lauss@googlemail.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/flash.h>
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/mach-au1x00/au1000.h>
|
||||
#include <asm/mach-au1x00/au1xxx_eth.h>
|
||||
#include <asm/mach-au1x00/au1xxx_dbdma.h>
|
||||
#include <asm/mach-au1x00/au1xxx_psc.h>
|
||||
#include <asm/mach-au1x00/au1550_spi.h>
|
||||
#include <asm/mach-au1x00/au1550nd.h>
|
||||
#include <asm/mach-db1x00/bcsr.h>
|
||||
#include <prom.h>
|
||||
#include "platform.h"
|
||||
|
||||
static void __init db1550_hw_setup(void)
|
||||
{
|
||||
void __iomem *base;
|
||||
unsigned long v;
|
||||
|
||||
/* complete pin setup: assign GPIO16 to PSC0_SYNC1 (SPI cs# line)
|
||||
* as well as PSC1_SYNC for AC97 on PB1550.
|
||||
*/
|
||||
v = alchemy_rdsys(AU1000_SYS_PINFUNC);
|
||||
alchemy_wrsys(v | 1 | SYS_PF_PSC1_S1, AU1000_SYS_PINFUNC);
|
||||
|
||||
/* reset the AC97 codec now, the reset time in the psc-ac97 driver
|
||||
* is apparently too short although it's ridiculous as it is.
|
||||
*/
|
||||
base = (void __iomem *)KSEG1ADDR(AU1550_PSC1_PHYS_ADDR);
|
||||
__raw_writel(PSC_SEL_CLK_SERCLK | PSC_SEL_PS_AC97MODE,
|
||||
base + PSC_SEL_OFFSET);
|
||||
__raw_writel(PSC_CTRL_DISABLE, base + PSC_CTRL_OFFSET);
|
||||
wmb();
|
||||
__raw_writel(PSC_AC97RST_RST, base + PSC_AC97RST_OFFSET);
|
||||
wmb();
|
||||
}
|
||||
|
||||
int __init db1550_board_setup(void)
|
||||
{
|
||||
unsigned short whoami;
|
||||
|
||||
bcsr_init(DB1550_BCSR_PHYS_ADDR,
|
||||
DB1550_BCSR_PHYS_ADDR + DB1550_BCSR_HEXLED_OFS);
|
||||
|
||||
whoami = bcsr_read(BCSR_WHOAMI); /* PB1550 hexled offset differs */
|
||||
switch (BCSR_WHOAMI_BOARD(whoami)) {
|
||||
case BCSR_WHOAMI_PB1550_SDR:
|
||||
case BCSR_WHOAMI_PB1550_DDR:
|
||||
bcsr_init(PB1550_BCSR_PHYS_ADDR,
|
||||
PB1550_BCSR_PHYS_ADDR + PB1550_BCSR_HEXLED_OFS);
|
||||
case BCSR_WHOAMI_DB1550:
|
||||
break;
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pr_info("Alchemy/AMD %s Board, CPLD Rev %d Board-ID %d " \
|
||||
"Daughtercard ID %d\n", get_system_type(),
|
||||
(whoami >> 4) & 0xf, (whoami >> 8) & 0xf, whoami & 0xf);
|
||||
|
||||
db1550_hw_setup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static struct mtd_partition db1550_spiflash_parts[] = {
|
||||
{
|
||||
.name = "spi_flash",
|
||||
.offset = 0,
|
||||
.size = MTDPART_SIZ_FULL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct flash_platform_data db1550_spiflash_data = {
|
||||
.name = "s25fl010",
|
||||
.parts = db1550_spiflash_parts,
|
||||
.nr_parts = ARRAY_SIZE(db1550_spiflash_parts),
|
||||
.type = "m25p10",
|
||||
};
|
||||
|
||||
static struct spi_board_info db1550_spi_devs[] __initdata = {
|
||||
{
|
||||
/* TI TMP121AIDBVR temp sensor */
|
||||
.modalias = "tmp121",
|
||||
.max_speed_hz = 2400000,
|
||||
.bus_num = 0,
|
||||
.chip_select = 0,
|
||||
.mode = SPI_MODE_0,
|
||||
},
|
||||
{
|
||||
/* Spansion S25FL001D0FMA SPI flash */
|
||||
.modalias = "m25p80",
|
||||
.max_speed_hz = 2400000,
|
||||
.bus_num = 0,
|
||||
.chip_select = 1,
|
||||
.mode = SPI_MODE_0,
|
||||
.platform_data = &db1550_spiflash_data,
|
||||
},
|
||||
};
|
||||
|
||||
static struct i2c_board_info db1550_i2c_devs[] __initdata = {
|
||||
{ I2C_BOARD_INFO("24c04", 0x52),}, /* AT24C04-10 I2C eeprom */
|
||||
{ I2C_BOARD_INFO("ne1619", 0x2d),}, /* adm1025-compat hwmon */
|
||||
{ I2C_BOARD_INFO("wm8731", 0x1b),}, /* I2S audio codec WM8731 */
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static void au1550_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
unsigned long ioaddr = (unsigned long)this->IO_ADDR_W;
|
||||
|
||||
ioaddr &= 0xffffff00;
|
||||
|
||||
if (ctrl & NAND_CLE) {
|
||||
ioaddr += MEM_STNAND_CMD;
|
||||
} else if (ctrl & NAND_ALE) {
|
||||
ioaddr += MEM_STNAND_ADDR;
|
||||
} else {
|
||||
/* assume we want to r/w real data by default */
|
||||
ioaddr += MEM_STNAND_DATA;
|
||||
}
|
||||
this->IO_ADDR_R = this->IO_ADDR_W = (void __iomem *)ioaddr;
|
||||
if (cmd != NAND_CMD_NONE) {
|
||||
__raw_writeb(cmd, this->IO_ADDR_W);
|
||||
wmb();
|
||||
}
|
||||
}
|
||||
|
||||
static int au1550_nand_device_ready(struct mtd_info *mtd)
|
||||
{
|
||||
return alchemy_rdsmem(AU1000_MEM_STSTAT) & 1;
|
||||
}
|
||||
|
||||
static struct mtd_partition db1550_nand_parts[] = {
|
||||
{
|
||||
.name = "NAND FS 0",
|
||||
.offset = 0,
|
||||
.size = 8 * 1024 * 1024,
|
||||
},
|
||||
{
|
||||
.name = "NAND FS 1",
|
||||
.offset = MTDPART_OFS_APPEND,
|
||||
.size = MTDPART_SIZ_FULL
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_nand_data db1550_nand_platdata = {
|
||||
.chip = {
|
||||
.nr_chips = 1,
|
||||
.chip_offset = 0,
|
||||
.nr_partitions = ARRAY_SIZE(db1550_nand_parts),
|
||||
.partitions = db1550_nand_parts,
|
||||
.chip_delay = 20,
|
||||
},
|
||||
.ctrl = {
|
||||
.dev_ready = au1550_nand_device_ready,
|
||||
.cmd_ctrl = au1550_nand_cmd_ctrl,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource db1550_nand_res[] = {
|
||||
[0] = {
|
||||
.start = 0x20000000,
|
||||
.end = 0x200000ff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device db1550_nand_dev = {
|
||||
.name = "gen_nand",
|
||||
.num_resources = ARRAY_SIZE(db1550_nand_res),
|
||||
.resource = db1550_nand_res,
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.platform_data = &db1550_nand_platdata,
|
||||
}
|
||||
};
|
||||
|
||||
static struct au1550nd_platdata pb1550_nand_pd = {
|
||||
.parts = db1550_nand_parts,
|
||||
.num_parts = ARRAY_SIZE(db1550_nand_parts),
|
||||
.devwidth = 0, /* x8 NAND default, needs fixing up */
|
||||
};
|
||||
|
||||
static struct platform_device pb1550_nand_dev = {
|
||||
.name = "au1550-nand",
|
||||
.id = -1,
|
||||
.resource = db1550_nand_res,
|
||||
.num_resources = ARRAY_SIZE(db1550_nand_res),
|
||||
.dev = {
|
||||
.platform_data = &pb1550_nand_pd,
|
||||
},
|
||||
};
|
||||
|
||||
static void __init pb1550_nand_setup(void)
|
||||
{
|
||||
int boot_swapboot = (alchemy_rdsmem(AU1000_MEM_STSTAT) & (0x7 << 1)) |
|
||||
((bcsr_read(BCSR_STATUS) >> 6) & 0x1);
|
||||
|
||||
gpio_direction_input(206); /* de-assert NAND CS# */
|
||||
switch (boot_swapboot) {
|
||||
case 0: case 2: case 8: case 0xC: case 0xD:
|
||||
/* x16 NAND Flash */
|
||||
pb1550_nand_pd.devwidth = 1;
|
||||
/* fallthrough */
|
||||
case 1: case 3: case 9: case 0xE: case 0xF:
|
||||
/* x8 NAND, already set up */
|
||||
platform_device_register(&pb1550_nand_dev);
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static struct resource au1550_psc0_res[] = {
|
||||
[0] = {
|
||||
.start = AU1550_PSC0_PHYS_ADDR,
|
||||
.end = AU1550_PSC0_PHYS_ADDR + 0xfff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = AU1550_PSC0_INT,
|
||||
.end = AU1550_PSC0_INT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[2] = {
|
||||
.start = AU1550_DSCR_CMD0_PSC0_TX,
|
||||
.end = AU1550_DSCR_CMD0_PSC0_TX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[3] = {
|
||||
.start = AU1550_DSCR_CMD0_PSC0_RX,
|
||||
.end = AU1550_DSCR_CMD0_PSC0_RX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
static void db1550_spi_cs_en(struct au1550_spi_info *spi, int cs, int pol)
|
||||
{
|
||||
if (cs)
|
||||
bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_SPISEL);
|
||||
else
|
||||
bcsr_mod(BCSR_BOARD, BCSR_BOARD_SPISEL, 0);
|
||||
}
|
||||
|
||||
static struct au1550_spi_info db1550_spi_platdata = {
|
||||
.mainclk_hz = 48000000, /* PSC0 clock: max. 2.4MHz SPI clk */
|
||||
.num_chipselect = 2,
|
||||
.activate_cs = db1550_spi_cs_en,
|
||||
};
|
||||
|
||||
static u64 spi_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
static struct platform_device db1550_spi_dev = {
|
||||
.dev = {
|
||||
.dma_mask = &spi_dmamask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
.platform_data = &db1550_spi_platdata,
|
||||
},
|
||||
.name = "au1550-spi",
|
||||
.id = 0, /* bus number */
|
||||
.num_resources = ARRAY_SIZE(au1550_psc0_res),
|
||||
.resource = au1550_psc0_res,
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static struct resource au1550_psc1_res[] = {
|
||||
[0] = {
|
||||
.start = AU1550_PSC1_PHYS_ADDR,
|
||||
.end = AU1550_PSC1_PHYS_ADDR + 0xfff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = AU1550_PSC1_INT,
|
||||
.end = AU1550_PSC1_INT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[2] = {
|
||||
.start = AU1550_DSCR_CMD0_PSC1_TX,
|
||||
.end = AU1550_DSCR_CMD0_PSC1_TX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[3] = {
|
||||
.start = AU1550_DSCR_CMD0_PSC1_RX,
|
||||
.end = AU1550_DSCR_CMD0_PSC1_RX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device db1550_ac97_dev = {
|
||||
.name = "au1xpsc_ac97",
|
||||
.id = 1, /* PSC ID */
|
||||
.num_resources = ARRAY_SIZE(au1550_psc1_res),
|
||||
.resource = au1550_psc1_res,
|
||||
};
|
||||
|
||||
|
||||
static struct resource au1550_psc2_res[] = {
|
||||
[0] = {
|
||||
.start = AU1550_PSC2_PHYS_ADDR,
|
||||
.end = AU1550_PSC2_PHYS_ADDR + 0xfff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = AU1550_PSC2_INT,
|
||||
.end = AU1550_PSC2_INT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[2] = {
|
||||
.start = AU1550_DSCR_CMD0_PSC2_TX,
|
||||
.end = AU1550_DSCR_CMD0_PSC2_TX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[3] = {
|
||||
.start = AU1550_DSCR_CMD0_PSC2_RX,
|
||||
.end = AU1550_DSCR_CMD0_PSC2_RX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device db1550_i2c_dev = {
|
||||
.name = "au1xpsc_smbus",
|
||||
.id = 0, /* bus number */
|
||||
.num_resources = ARRAY_SIZE(au1550_psc2_res),
|
||||
.resource = au1550_psc2_res,
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static struct resource au1550_psc3_res[] = {
|
||||
[0] = {
|
||||
.start = AU1550_PSC3_PHYS_ADDR,
|
||||
.end = AU1550_PSC3_PHYS_ADDR + 0xfff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = AU1550_PSC3_INT,
|
||||
.end = AU1550_PSC3_INT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[2] = {
|
||||
.start = AU1550_DSCR_CMD0_PSC3_TX,
|
||||
.end = AU1550_DSCR_CMD0_PSC3_TX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[3] = {
|
||||
.start = AU1550_DSCR_CMD0_PSC3_RX,
|
||||
.end = AU1550_DSCR_CMD0_PSC3_RX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device db1550_i2s_dev = {
|
||||
.name = "au1xpsc_i2s",
|
||||
.id = 3, /* PSC ID */
|
||||
.num_resources = ARRAY_SIZE(au1550_psc3_res),
|
||||
.resource = au1550_psc3_res,
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static struct platform_device db1550_stac_dev = {
|
||||
.name = "ac97-codec",
|
||||
.id = 1, /* on PSC1 */
|
||||
};
|
||||
|
||||
static struct platform_device db1550_ac97dma_dev = {
|
||||
.name = "au1xpsc-pcm",
|
||||
.id = 1, /* on PSC3 */
|
||||
};
|
||||
|
||||
static struct platform_device db1550_i2sdma_dev = {
|
||||
.name = "au1xpsc-pcm",
|
||||
.id = 3, /* on PSC3 */
|
||||
};
|
||||
|
||||
static struct platform_device db1550_sndac97_dev = {
|
||||
.name = "db1550-ac97",
|
||||
};
|
||||
|
||||
static struct platform_device db1550_sndi2s_dev = {
|
||||
.name = "db1550-i2s",
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static int db1550_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin)
|
||||
{
|
||||
if ((slot < 11) || (slot > 13) || pin == 0)
|
||||
return -1;
|
||||
if (slot == 11)
|
||||
return (pin == 1) ? AU1550_PCI_INTC : 0xff;
|
||||
if (slot == 12) {
|
||||
switch (pin) {
|
||||
case 1: return AU1550_PCI_INTB;
|
||||
case 2: return AU1550_PCI_INTC;
|
||||
case 3: return AU1550_PCI_INTD;
|
||||
case 4: return AU1550_PCI_INTA;
|
||||
}
|
||||
}
|
||||
if (slot == 13) {
|
||||
switch (pin) {
|
||||
case 1: return AU1550_PCI_INTA;
|
||||
case 2: return AU1550_PCI_INTB;
|
||||
case 3: return AU1550_PCI_INTC;
|
||||
case 4: return AU1550_PCI_INTD;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int pb1550_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin)
|
||||
{
|
||||
if ((slot < 12) || (slot > 13) || pin == 0)
|
||||
return -1;
|
||||
if (slot == 12) {
|
||||
switch (pin) {
|
||||
case 1: return AU1500_PCI_INTB;
|
||||
case 2: return AU1500_PCI_INTC;
|
||||
case 3: return AU1500_PCI_INTD;
|
||||
case 4: return AU1500_PCI_INTA;
|
||||
}
|
||||
}
|
||||
if (slot == 13) {
|
||||
switch (pin) {
|
||||
case 1: return AU1500_PCI_INTA;
|
||||
case 2: return AU1500_PCI_INTB;
|
||||
case 3: return AU1500_PCI_INTC;
|
||||
case 4: return AU1500_PCI_INTD;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct resource alchemy_pci_host_res[] = {
|
||||
[0] = {
|
||||
.start = AU1500_PCI_PHYS_ADDR,
|
||||
.end = AU1500_PCI_PHYS_ADDR + 0xfff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct alchemy_pci_platdata db1550_pci_pd = {
|
||||
.board_map_irq = db1550_map_pci_irq,
|
||||
};
|
||||
|
||||
static struct platform_device db1550_pci_host_dev = {
|
||||
.dev.platform_data = &db1550_pci_pd,
|
||||
.name = "alchemy-pci",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(alchemy_pci_host_res),
|
||||
.resource = alchemy_pci_host_res,
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static struct platform_device *db1550_devs[] __initdata = {
|
||||
&db1550_i2c_dev,
|
||||
&db1550_ac97_dev,
|
||||
&db1550_spi_dev,
|
||||
&db1550_i2s_dev,
|
||||
&db1550_stac_dev,
|
||||
&db1550_ac97dma_dev,
|
||||
&db1550_i2sdma_dev,
|
||||
&db1550_sndac97_dev,
|
||||
&db1550_sndi2s_dev,
|
||||
};
|
||||
|
||||
/* must be arch_initcall; MIPS PCI scans busses in a subsys_initcall */
|
||||
int __init db1550_pci_setup(int id)
|
||||
{
|
||||
if (id)
|
||||
db1550_pci_pd.board_map_irq = pb1550_map_pci_irq;
|
||||
return platform_device_register(&db1550_pci_host_dev);
|
||||
}
|
||||
|
||||
static void __init db1550_devices(void)
|
||||
{
|
||||
alchemy_gpio_direction_output(203, 0); /* red led on */
|
||||
|
||||
irq_set_irq_type(AU1550_GPIO0_INT, IRQ_TYPE_EDGE_BOTH); /* CD0# */
|
||||
irq_set_irq_type(AU1550_GPIO1_INT, IRQ_TYPE_EDGE_BOTH); /* CD1# */
|
||||
irq_set_irq_type(AU1550_GPIO3_INT, IRQ_TYPE_LEVEL_LOW); /* CARD0# */
|
||||
irq_set_irq_type(AU1550_GPIO5_INT, IRQ_TYPE_LEVEL_LOW); /* CARD1# */
|
||||
irq_set_irq_type(AU1550_GPIO21_INT, IRQ_TYPE_LEVEL_LOW); /* STSCHG0# */
|
||||
irq_set_irq_type(AU1550_GPIO22_INT, IRQ_TYPE_LEVEL_LOW); /* STSCHG1# */
|
||||
|
||||
db1x_register_pcmcia_socket(
|
||||
AU1000_PCMCIA_ATTR_PHYS_ADDR,
|
||||
AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
|
||||
AU1000_PCMCIA_MEM_PHYS_ADDR,
|
||||
AU1000_PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1,
|
||||
AU1000_PCMCIA_IO_PHYS_ADDR,
|
||||
AU1000_PCMCIA_IO_PHYS_ADDR + 0x000010000 - 1,
|
||||
AU1550_GPIO3_INT, AU1550_GPIO0_INT,
|
||||
/*AU1550_GPIO21_INT*/0, 0, 0);
|
||||
|
||||
db1x_register_pcmcia_socket(
|
||||
AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004000000,
|
||||
AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004400000 - 1,
|
||||
AU1000_PCMCIA_MEM_PHYS_ADDR + 0x004000000,
|
||||
AU1000_PCMCIA_MEM_PHYS_ADDR + 0x004400000 - 1,
|
||||
AU1000_PCMCIA_IO_PHYS_ADDR + 0x004000000,
|
||||
AU1000_PCMCIA_IO_PHYS_ADDR + 0x004010000 - 1,
|
||||
AU1550_GPIO5_INT, AU1550_GPIO1_INT,
|
||||
/*AU1550_GPIO22_INT*/0, 0, 1);
|
||||
|
||||
platform_device_register(&db1550_nand_dev);
|
||||
|
||||
alchemy_gpio_direction_output(202, 0); /* green led on */
|
||||
}
|
||||
|
||||
static void __init pb1550_devices(void)
|
||||
{
|
||||
irq_set_irq_type(AU1550_GPIO0_INT, IRQ_TYPE_LEVEL_LOW);
|
||||
irq_set_irq_type(AU1550_GPIO1_INT, IRQ_TYPE_LEVEL_LOW);
|
||||
irq_set_irq_type(AU1550_GPIO201_205_INT, IRQ_TYPE_LEVEL_HIGH);
|
||||
|
||||
/* enable both PCMCIA card irqs in the shared line */
|
||||
alchemy_gpio2_enable_int(201); /* socket 0 card irq */
|
||||
alchemy_gpio2_enable_int(202); /* socket 1 card irq */
|
||||
|
||||
/* Pb1550, like all others, also has statuschange irqs; however they're
|
||||
* wired up on one of the Au1550's shared GPIO201_205 line, which also
|
||||
* services the PCMCIA card interrupts. So we ignore statuschange and
|
||||
* use the GPIO201_205 exclusively for card interrupts, since a) pcmcia
|
||||
* drivers are used to shared irqs and b) statuschange isn't really use-
|
||||
* ful anyway.
|
||||
*/
|
||||
db1x_register_pcmcia_socket(
|
||||
AU1000_PCMCIA_ATTR_PHYS_ADDR,
|
||||
AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
|
||||
AU1000_PCMCIA_MEM_PHYS_ADDR,
|
||||
AU1000_PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1,
|
||||
AU1000_PCMCIA_IO_PHYS_ADDR,
|
||||
AU1000_PCMCIA_IO_PHYS_ADDR + 0x000010000 - 1,
|
||||
AU1550_GPIO201_205_INT, AU1550_GPIO0_INT, 0, 0, 0);
|
||||
|
||||
db1x_register_pcmcia_socket(
|
||||
AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x008000000,
|
||||
AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x008400000 - 1,
|
||||
AU1000_PCMCIA_MEM_PHYS_ADDR + 0x008000000,
|
||||
AU1000_PCMCIA_MEM_PHYS_ADDR + 0x008400000 - 1,
|
||||
AU1000_PCMCIA_IO_PHYS_ADDR + 0x008000000,
|
||||
AU1000_PCMCIA_IO_PHYS_ADDR + 0x008010000 - 1,
|
||||
AU1550_GPIO201_205_INT, AU1550_GPIO1_INT, 0, 0, 1);
|
||||
|
||||
pb1550_nand_setup();
|
||||
}
|
||||
|
||||
int __init db1550_dev_setup(void)
|
||||
{
|
||||
int swapped, id;
|
||||
struct clk *c;
|
||||
|
||||
id = (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI)) != BCSR_WHOAMI_DB1550);
|
||||
|
||||
i2c_register_board_info(0, db1550_i2c_devs,
|
||||
ARRAY_SIZE(db1550_i2c_devs));
|
||||
spi_register_board_info(db1550_spi_devs,
|
||||
ARRAY_SIZE(db1550_i2c_devs));
|
||||
|
||||
c = clk_get(NULL, "psc0_intclk");
|
||||
if (!IS_ERR(c)) {
|
||||
clk_set_rate(c, 50000000);
|
||||
clk_prepare_enable(c);
|
||||
clk_put(c);
|
||||
}
|
||||
c = clk_get(NULL, "psc2_intclk");
|
||||
if (!IS_ERR(c)) {
|
||||
clk_set_rate(c, db1550_spi_platdata.mainclk_hz);
|
||||
clk_prepare_enable(c);
|
||||
clk_put(c);
|
||||
}
|
||||
|
||||
/* Audio PSC clock is supplied by codecs (PSC1, 3) FIXME: platdata!! */
|
||||
__raw_writel(PSC_SEL_CLK_SERCLK,
|
||||
(void __iomem *)KSEG1ADDR(AU1550_PSC1_PHYS_ADDR) + PSC_SEL_OFFSET);
|
||||
wmb();
|
||||
__raw_writel(PSC_SEL_CLK_SERCLK,
|
||||
(void __iomem *)KSEG1ADDR(AU1550_PSC3_PHYS_ADDR) + PSC_SEL_OFFSET);
|
||||
wmb();
|
||||
/* SPI/I2C use internally supplied 50MHz source */
|
||||
__raw_writel(PSC_SEL_CLK_INTCLK,
|
||||
(void __iomem *)KSEG1ADDR(AU1550_PSC0_PHYS_ADDR) + PSC_SEL_OFFSET);
|
||||
wmb();
|
||||
__raw_writel(PSC_SEL_CLK_INTCLK,
|
||||
(void __iomem *)KSEG1ADDR(AU1550_PSC2_PHYS_ADDR) + PSC_SEL_OFFSET);
|
||||
wmb();
|
||||
|
||||
id ? pb1550_devices() : db1550_devices();
|
||||
|
||||
swapped = bcsr_read(BCSR_STATUS) &
|
||||
(id ? BCSR_STATUS_PB1550_SWAPBOOT : BCSR_STATUS_DB1000_SWAPBOOT);
|
||||
db1x_register_norflash(128 << 20, 4, swapped);
|
||||
|
||||
return platform_add_devices(db1550_devs, ARRAY_SIZE(db1550_devs));
|
||||
}
|
121
arch/mips/alchemy/devboards/db1xxx.c
Normal file
121
arch/mips/alchemy/devboards/db1xxx.c
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Alchemy DB/PB1xxx board support.
|
||||
*/
|
||||
|
||||
#include <asm/mach-au1x00/au1000.h>
|
||||
#include <asm/mach-db1x00/bcsr.h>
|
||||
|
||||
int __init db1000_board_setup(void);
|
||||
int __init db1000_dev_setup(void);
|
||||
int __init db1500_pci_setup(void);
|
||||
int __init db1200_board_setup(void);
|
||||
int __init db1200_dev_setup(void);
|
||||
int __init db1300_board_setup(void);
|
||||
int __init db1300_dev_setup(void);
|
||||
int __init db1550_board_setup(void);
|
||||
int __init db1550_dev_setup(void);
|
||||
int __init db1550_pci_setup(int);
|
||||
|
||||
static const char *board_type_str(void)
|
||||
{
|
||||
switch (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI))) {
|
||||
case BCSR_WHOAMI_DB1000:
|
||||
return "DB1000";
|
||||
case BCSR_WHOAMI_DB1500:
|
||||
return "DB1500";
|
||||
case BCSR_WHOAMI_DB1100:
|
||||
return "DB1100";
|
||||
case BCSR_WHOAMI_PB1500:
|
||||
case BCSR_WHOAMI_PB1500R2:
|
||||
return "PB1500";
|
||||
case BCSR_WHOAMI_PB1100:
|
||||
return "PB1100";
|
||||
case BCSR_WHOAMI_PB1200_DDR1:
|
||||
case BCSR_WHOAMI_PB1200_DDR2:
|
||||
return "PB1200";
|
||||
case BCSR_WHOAMI_DB1200:
|
||||
return "DB1200";
|
||||
case BCSR_WHOAMI_DB1300:
|
||||
return "DB1300";
|
||||
case BCSR_WHOAMI_DB1550:
|
||||
return "DB1550";
|
||||
case BCSR_WHOAMI_PB1550_SDR:
|
||||
case BCSR_WHOAMI_PB1550_DDR:
|
||||
return "PB1550";
|
||||
default:
|
||||
return "(unknown)";
|
||||
}
|
||||
}
|
||||
|
||||
const char *get_system_type(void)
|
||||
{
|
||||
return board_type_str();
|
||||
}
|
||||
|
||||
void __init board_setup(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (alchemy_get_cputype()) {
|
||||
case ALCHEMY_CPU_AU1000:
|
||||
case ALCHEMY_CPU_AU1500:
|
||||
case ALCHEMY_CPU_AU1100:
|
||||
ret = db1000_board_setup();
|
||||
break;
|
||||
case ALCHEMY_CPU_AU1550:
|
||||
ret = db1550_board_setup();
|
||||
break;
|
||||
case ALCHEMY_CPU_AU1200:
|
||||
ret = db1200_board_setup();
|
||||
break;
|
||||
case ALCHEMY_CPU_AU1300:
|
||||
ret = db1300_board_setup();
|
||||
break;
|
||||
default:
|
||||
pr_err("unsupported CPU on board\n");
|
||||
ret = -ENODEV;
|
||||
}
|
||||
if (ret)
|
||||
panic("cannot initialize board support");
|
||||
}
|
||||
|
||||
static int __init db1xxx_arch_init(void)
|
||||
{
|
||||
int id = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI));
|
||||
if (id == BCSR_WHOAMI_DB1550)
|
||||
return db1550_pci_setup(0);
|
||||
else if ((id == BCSR_WHOAMI_PB1550_SDR) ||
|
||||
(id == BCSR_WHOAMI_PB1550_DDR))
|
||||
return db1550_pci_setup(1);
|
||||
else if ((id == BCSR_WHOAMI_DB1500) || (id == BCSR_WHOAMI_PB1500) ||
|
||||
(id == BCSR_WHOAMI_PB1500R2))
|
||||
return db1500_pci_setup();
|
||||
|
||||
return 0;
|
||||
}
|
||||
arch_initcall(db1xxx_arch_init);
|
||||
|
||||
static int __init db1xxx_dev_init(void)
|
||||
{
|
||||
switch (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI))) {
|
||||
case BCSR_WHOAMI_DB1000:
|
||||
case BCSR_WHOAMI_DB1500:
|
||||
case BCSR_WHOAMI_DB1100:
|
||||
case BCSR_WHOAMI_PB1500:
|
||||
case BCSR_WHOAMI_PB1500R2:
|
||||
case BCSR_WHOAMI_PB1100:
|
||||
return db1000_dev_setup();
|
||||
case BCSR_WHOAMI_PB1200_DDR1:
|
||||
case BCSR_WHOAMI_PB1200_DDR2:
|
||||
case BCSR_WHOAMI_DB1200:
|
||||
return db1200_dev_setup();
|
||||
case BCSR_WHOAMI_DB1300:
|
||||
return db1300_dev_setup();
|
||||
case BCSR_WHOAMI_DB1550:
|
||||
case BCSR_WHOAMI_PB1550_SDR:
|
||||
case BCSR_WHOAMI_PB1550_DDR:
|
||||
return db1550_dev_setup();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
device_initcall(db1xxx_dev_init);
|
263
arch/mips/alchemy/devboards/platform.c
Normal file
263
arch/mips/alchemy/devboards/platform.c
Normal file
|
@ -0,0 +1,263 @@
|
|||
/*
|
||||
* devoard misc stuff.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/map.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/idle.h>
|
||||
#include <asm/reboot.h>
|
||||
#include <asm/mach-au1x00/au1000.h>
|
||||
#include <asm/mach-db1x00/bcsr.h>
|
||||
|
||||
#include <prom.h>
|
||||
|
||||
void __init prom_init(void)
|
||||
{
|
||||
unsigned char *memsize_str;
|
||||
unsigned long memsize;
|
||||
|
||||
prom_argc = (int)fw_arg0;
|
||||
prom_argv = (char **)fw_arg1;
|
||||
prom_envp = (char **)fw_arg2;
|
||||
|
||||
prom_init_cmdline();
|
||||
memsize_str = prom_getenv("memsize");
|
||||
if (!memsize_str || kstrtoul(memsize_str, 0, &memsize))
|
||||
memsize = 64 << 20; /* all devboards have at least 64MB RAM */
|
||||
|
||||
add_memory_region(0, memsize, BOOT_MEM_RAM);
|
||||
}
|
||||
|
||||
void prom_putchar(unsigned char c)
|
||||
{
|
||||
if (alchemy_get_cputype() == ALCHEMY_CPU_AU1300)
|
||||
alchemy_uart_putchar(AU1300_UART2_PHYS_ADDR, c);
|
||||
else
|
||||
alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c);
|
||||
}
|
||||
|
||||
|
||||
static struct platform_device db1x00_rtc_dev = {
|
||||
.name = "rtc-au1xxx",
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
|
||||
static void db1x_power_off(void)
|
||||
{
|
||||
bcsr_write(BCSR_RESETS, 0);
|
||||
bcsr_write(BCSR_SYSTEM, BCSR_SYSTEM_PWROFF | BCSR_SYSTEM_RESET);
|
||||
while (1) /* sit and spin */
|
||||
cpu_wait();
|
||||
}
|
||||
|
||||
static void db1x_reset(char *c)
|
||||
{
|
||||
bcsr_write(BCSR_RESETS, 0);
|
||||
bcsr_write(BCSR_SYSTEM, 0);
|
||||
}
|
||||
|
||||
static int __init db1x_late_setup(void)
|
||||
{
|
||||
if (!pm_power_off)
|
||||
pm_power_off = db1x_power_off;
|
||||
if (!_machine_halt)
|
||||
_machine_halt = db1x_power_off;
|
||||
if (!_machine_restart)
|
||||
_machine_restart = db1x_reset;
|
||||
|
||||
platform_device_register(&db1x00_rtc_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
device_initcall(db1x_late_setup);
|
||||
|
||||
/* register a pcmcia socket */
|
||||
int __init db1x_register_pcmcia_socket(phys_addr_t pcmcia_attr_start,
|
||||
phys_addr_t pcmcia_attr_end,
|
||||
phys_addr_t pcmcia_mem_start,
|
||||
phys_addr_t pcmcia_mem_end,
|
||||
phys_addr_t pcmcia_io_start,
|
||||
phys_addr_t pcmcia_io_end,
|
||||
int card_irq,
|
||||
int cd_irq,
|
||||
int stschg_irq,
|
||||
int eject_irq,
|
||||
int id)
|
||||
{
|
||||
int cnt, i, ret;
|
||||
struct resource *sr;
|
||||
struct platform_device *pd;
|
||||
|
||||
cnt = 5;
|
||||
if (eject_irq)
|
||||
cnt++;
|
||||
if (stschg_irq)
|
||||
cnt++;
|
||||
|
||||
sr = kzalloc(sizeof(struct resource) * cnt, GFP_KERNEL);
|
||||
if (!sr)
|
||||
return -ENOMEM;
|
||||
|
||||
pd = platform_device_alloc("db1xxx_pcmcia", id);
|
||||
if (!pd) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
sr[0].name = "pcmcia-attr";
|
||||
sr[0].flags = IORESOURCE_MEM;
|
||||
sr[0].start = pcmcia_attr_start;
|
||||
sr[0].end = pcmcia_attr_end;
|
||||
|
||||
sr[1].name = "pcmcia-mem";
|
||||
sr[1].flags = IORESOURCE_MEM;
|
||||
sr[1].start = pcmcia_mem_start;
|
||||
sr[1].end = pcmcia_mem_end;
|
||||
|
||||
sr[2].name = "pcmcia-io";
|
||||
sr[2].flags = IORESOURCE_MEM;
|
||||
sr[2].start = pcmcia_io_start;
|
||||
sr[2].end = pcmcia_io_end;
|
||||
|
||||
sr[3].name = "insert";
|
||||
sr[3].flags = IORESOURCE_IRQ;
|
||||
sr[3].start = sr[3].end = cd_irq;
|
||||
|
||||
sr[4].name = "card";
|
||||
sr[4].flags = IORESOURCE_IRQ;
|
||||
sr[4].start = sr[4].end = card_irq;
|
||||
|
||||
i = 5;
|
||||
if (stschg_irq) {
|
||||
sr[i].name = "stschg";
|
||||
sr[i].flags = IORESOURCE_IRQ;
|
||||
sr[i].start = sr[i].end = stschg_irq;
|
||||
i++;
|
||||
}
|
||||
if (eject_irq) {
|
||||
sr[i].name = "eject";
|
||||
sr[i].flags = IORESOURCE_IRQ;
|
||||
sr[i].start = sr[i].end = eject_irq;
|
||||
}
|
||||
|
||||
pd->resource = sr;
|
||||
pd->num_resources = cnt;
|
||||
|
||||
ret = platform_device_add(pd);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
platform_device_put(pd);
|
||||
out:
|
||||
kfree(sr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define YAMON_SIZE 0x00100000
|
||||
#define YAMON_ENV_SIZE 0x00040000
|
||||
|
||||
int __init db1x_register_norflash(unsigned long size, int width,
|
||||
int swapped)
|
||||
{
|
||||
struct physmap_flash_data *pfd;
|
||||
struct platform_device *pd;
|
||||
struct mtd_partition *parts;
|
||||
struct resource *res;
|
||||
int ret, i;
|
||||
|
||||
if (size < (8 * 1024 * 1024))
|
||||
return -EINVAL;
|
||||
|
||||
ret = -ENOMEM;
|
||||
parts = kzalloc(sizeof(struct mtd_partition) * 5, GFP_KERNEL);
|
||||
if (!parts)
|
||||
goto out;
|
||||
|
||||
res = kzalloc(sizeof(struct resource), GFP_KERNEL);
|
||||
if (!res)
|
||||
goto out1;
|
||||
|
||||
pfd = kzalloc(sizeof(struct physmap_flash_data), GFP_KERNEL);
|
||||
if (!pfd)
|
||||
goto out2;
|
||||
|
||||
pd = platform_device_alloc("physmap-flash", 0);
|
||||
if (!pd)
|
||||
goto out3;
|
||||
|
||||
/* NOR flash ends at 0x20000000, regardless of size */
|
||||
res->start = 0x20000000 - size;
|
||||
res->end = 0x20000000 - 1;
|
||||
res->flags = IORESOURCE_MEM;
|
||||
|
||||
/* partition setup. Most Develboards have a switch which allows
|
||||
* to swap the physical locations of the 2 NOR flash banks.
|
||||
*/
|
||||
i = 0;
|
||||
if (!swapped) {
|
||||
/* first NOR chip */
|
||||
parts[i].offset = 0;
|
||||
parts[i].name = "User FS";
|
||||
parts[i].size = size / 2;
|
||||
i++;
|
||||
}
|
||||
|
||||
parts[i].offset = MTDPART_OFS_APPEND;
|
||||
parts[i].name = "User FS 2";
|
||||
parts[i].size = (size / 2) - (0x20000000 - 0x1fc00000);
|
||||
i++;
|
||||
|
||||
parts[i].offset = MTDPART_OFS_APPEND;
|
||||
parts[i].name = "YAMON";
|
||||
parts[i].size = YAMON_SIZE;
|
||||
parts[i].mask_flags = MTD_WRITEABLE;
|
||||
i++;
|
||||
|
||||
parts[i].offset = MTDPART_OFS_APPEND;
|
||||
parts[i].name = "raw kernel";
|
||||
parts[i].size = 0x00400000 - YAMON_SIZE - YAMON_ENV_SIZE;
|
||||
i++;
|
||||
|
||||
parts[i].offset = MTDPART_OFS_APPEND;
|
||||
parts[i].name = "YAMON Env";
|
||||
parts[i].size = YAMON_ENV_SIZE;
|
||||
parts[i].mask_flags = MTD_WRITEABLE;
|
||||
i++;
|
||||
|
||||
if (swapped) {
|
||||
parts[i].offset = MTDPART_OFS_APPEND;
|
||||
parts[i].name = "User FS";
|
||||
parts[i].size = size / 2;
|
||||
i++;
|
||||
}
|
||||
|
||||
pfd->width = width;
|
||||
pfd->parts = parts;
|
||||
pfd->nr_parts = 5;
|
||||
|
||||
pd->dev.platform_data = pfd;
|
||||
pd->resource = res;
|
||||
pd->num_resources = 1;
|
||||
|
||||
ret = platform_device_add(pd);
|
||||
if (!ret)
|
||||
return ret;
|
||||
|
||||
platform_device_put(pd);
|
||||
out3:
|
||||
kfree(pfd);
|
||||
out2:
|
||||
kfree(res);
|
||||
out1:
|
||||
kfree(parts);
|
||||
out:
|
||||
return ret;
|
||||
}
|
21
arch/mips/alchemy/devboards/platform.h
Normal file
21
arch/mips/alchemy/devboards/platform.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#ifndef _DEVBOARD_PLATFORM_H_
|
||||
#define _DEVBOARD_PLATFORM_H_
|
||||
|
||||
#include <linux/init.h>
|
||||
|
||||
int __init db1x_register_pcmcia_socket(phys_addr_t pcmcia_attr_start,
|
||||
phys_addr_t pcmcia_attr_len,
|
||||
phys_addr_t pcmcia_mem_start,
|
||||
phys_addr_t pcmcia_mem_end,
|
||||
phys_addr_t pcmcia_io_start,
|
||||
phys_addr_t pcmcia_io_end,
|
||||
int card_irq,
|
||||
int cd_irq,
|
||||
int stschg_irq,
|
||||
int eject_irq,
|
||||
int id);
|
||||
|
||||
int __init db1x_register_norflash(unsigned long size, int width,
|
||||
int swapped);
|
||||
|
||||
#endif
|
253
arch/mips/alchemy/devboards/pm.c
Normal file
253
arch/mips/alchemy/devboards/pm.c
Normal file
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
* Alchemy Development Board example suspend userspace interface.
|
||||
*
|
||||
* (c) 2008 Manuel Lauss <mano@roarinelk.homelinux.net>
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <asm/mach-au1x00/au1000.h>
|
||||
#include <asm/mach-au1x00/gpio.h>
|
||||
#include <asm/mach-db1x00/bcsr.h>
|
||||
|
||||
/*
|
||||
* Generic suspend userspace interface for Alchemy development boards.
|
||||
* This code exports a few sysfs nodes under /sys/power/db1x/ which
|
||||
* can be used by userspace to en/disable all au1x-provided wakeup
|
||||
* sources and configure the timeout after which the the TOYMATCH2 irq
|
||||
* is to trigger a wakeup.
|
||||
*/
|
||||
|
||||
|
||||
static unsigned long db1x_pm_sleep_secs;
|
||||
static unsigned long db1x_pm_wakemsk;
|
||||
static unsigned long db1x_pm_last_wakesrc;
|
||||
|
||||
static int db1x_pm_enter(suspend_state_t state)
|
||||
{
|
||||
unsigned short bcsrs[16];
|
||||
int i, j, hasint;
|
||||
|
||||
/* save CPLD regs */
|
||||
hasint = bcsr_read(BCSR_WHOAMI);
|
||||
hasint = BCSR_WHOAMI_BOARD(hasint) >= BCSR_WHOAMI_DB1200;
|
||||
j = (hasint) ? BCSR_MASKSET : BCSR_SYSTEM;
|
||||
|
||||
for (i = BCSR_STATUS; i <= j; i++)
|
||||
bcsrs[i] = bcsr_read(i);
|
||||
|
||||
/* shut off hexleds */
|
||||
bcsr_write(BCSR_HEXCLEAR, 3);
|
||||
|
||||
/* enable GPIO based wakeup */
|
||||
alchemy_gpio1_input_enable();
|
||||
|
||||
/* clear and setup wake cause and source */
|
||||
alchemy_wrsys(0, AU1000_SYS_WAKEMSK);
|
||||
alchemy_wrsys(0, AU1000_SYS_WAKESRC);
|
||||
|
||||
alchemy_wrsys(db1x_pm_wakemsk, AU1000_SYS_WAKEMSK);
|
||||
|
||||
/* setup 1Hz-timer-based wakeup: wait for reg access */
|
||||
while (alchemy_rdsys(AU1000_SYS_CNTRCTRL) & SYS_CNTRL_M20)
|
||||
asm volatile ("nop");
|
||||
|
||||
alchemy_wrsys(alchemy_rdsys(AU1000_SYS_TOYREAD) + db1x_pm_sleep_secs,
|
||||
AU1000_SYS_TOYMATCH2);
|
||||
|
||||
/* wait for value to really hit the register */
|
||||
while (alchemy_rdsys(AU1000_SYS_CNTRCTRL) & SYS_CNTRL_M20)
|
||||
asm volatile ("nop");
|
||||
|
||||
/* ...and now the sandman can come! */
|
||||
au_sleep();
|
||||
|
||||
|
||||
/* restore CPLD regs */
|
||||
for (i = BCSR_STATUS; i <= BCSR_SYSTEM; i++)
|
||||
bcsr_write(i, bcsrs[i]);
|
||||
|
||||
/* restore CPLD int registers */
|
||||
if (hasint) {
|
||||
bcsr_write(BCSR_INTCLR, 0xffff);
|
||||
bcsr_write(BCSR_MASKCLR, 0xffff);
|
||||
bcsr_write(BCSR_INTSTAT, 0xffff);
|
||||
bcsr_write(BCSR_INTSET, bcsrs[BCSR_INTSET]);
|
||||
bcsr_write(BCSR_MASKSET, bcsrs[BCSR_MASKSET]);
|
||||
}
|
||||
|
||||
/* light up hexleds */
|
||||
bcsr_write(BCSR_HEXCLEAR, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int db1x_pm_begin(suspend_state_t state)
|
||||
{
|
||||
if (!db1x_pm_wakemsk) {
|
||||
printk(KERN_ERR "db1x: no wakeup source activated!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void db1x_pm_end(void)
|
||||
{
|
||||
/* read and store wakeup source, the clear the register. To
|
||||
* be able to clear it, WAKEMSK must be cleared first.
|
||||
*/
|
||||
db1x_pm_last_wakesrc = alchemy_rdsys(AU1000_SYS_WAKESRC);
|
||||
|
||||
alchemy_wrsys(0, AU1000_SYS_WAKEMSK);
|
||||
alchemy_wrsys(0, AU1000_SYS_WAKESRC);
|
||||
}
|
||||
|
||||
static const struct platform_suspend_ops db1x_pm_ops = {
|
||||
.valid = suspend_valid_only_mem,
|
||||
.begin = db1x_pm_begin,
|
||||
.enter = db1x_pm_enter,
|
||||
.end = db1x_pm_end,
|
||||
};
|
||||
|
||||
#define ATTRCMP(x) (0 == strcmp(attr->attr.name, #x))
|
||||
|
||||
static ssize_t db1x_pmattr_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int idx;
|
||||
|
||||
if (ATTRCMP(timer_timeout))
|
||||
return sprintf(buf, "%lu\n", db1x_pm_sleep_secs);
|
||||
|
||||
else if (ATTRCMP(timer))
|
||||
return sprintf(buf, "%u\n",
|
||||
!!(db1x_pm_wakemsk & SYS_WAKEMSK_M2));
|
||||
|
||||
else if (ATTRCMP(wakesrc))
|
||||
return sprintf(buf, "%lu\n", db1x_pm_last_wakesrc);
|
||||
|
||||
else if (ATTRCMP(gpio0) || ATTRCMP(gpio1) || ATTRCMP(gpio2) ||
|
||||
ATTRCMP(gpio3) || ATTRCMP(gpio4) || ATTRCMP(gpio5) ||
|
||||
ATTRCMP(gpio6) || ATTRCMP(gpio7)) {
|
||||
idx = (attr->attr.name)[4] - '0';
|
||||
return sprintf(buf, "%d\n",
|
||||
!!(db1x_pm_wakemsk & SYS_WAKEMSK_GPIO(idx)));
|
||||
|
||||
} else if (ATTRCMP(wakemsk)) {
|
||||
return sprintf(buf, "%08lx\n", db1x_pm_wakemsk);
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static ssize_t db1x_pmattr_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
const char *instr,
|
||||
size_t bytes)
|
||||
{
|
||||
unsigned long l;
|
||||
int tmp;
|
||||
|
||||
if (ATTRCMP(timer_timeout)) {
|
||||
tmp = kstrtoul(instr, 0, &l);
|
||||
if (tmp)
|
||||
return tmp;
|
||||
|
||||
db1x_pm_sleep_secs = l;
|
||||
|
||||
} else if (ATTRCMP(timer)) {
|
||||
if (instr[0] != '0')
|
||||
db1x_pm_wakemsk |= SYS_WAKEMSK_M2;
|
||||
else
|
||||
db1x_pm_wakemsk &= ~SYS_WAKEMSK_M2;
|
||||
|
||||
} else if (ATTRCMP(gpio0) || ATTRCMP(gpio1) || ATTRCMP(gpio2) ||
|
||||
ATTRCMP(gpio3) || ATTRCMP(gpio4) || ATTRCMP(gpio5) ||
|
||||
ATTRCMP(gpio6) || ATTRCMP(gpio7)) {
|
||||
tmp = (attr->attr.name)[4] - '0';
|
||||
if (instr[0] != '0') {
|
||||
db1x_pm_wakemsk |= SYS_WAKEMSK_GPIO(tmp);
|
||||
} else {
|
||||
db1x_pm_wakemsk &= ~SYS_WAKEMSK_GPIO(tmp);
|
||||
}
|
||||
|
||||
} else if (ATTRCMP(wakemsk)) {
|
||||
tmp = kstrtoul(instr, 0, &l);
|
||||
if (tmp)
|
||||
return tmp;
|
||||
|
||||
db1x_pm_wakemsk = l & 0x0000003f;
|
||||
|
||||
} else
|
||||
bytes = -ENOENT;
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
#define ATTR(x) \
|
||||
static struct kobj_attribute x##_attribute = \
|
||||
__ATTR(x, 0664, db1x_pmattr_show, \
|
||||
db1x_pmattr_store);
|
||||
|
||||
ATTR(gpio0) /* GPIO-based wakeup enable */
|
||||
ATTR(gpio1)
|
||||
ATTR(gpio2)
|
||||
ATTR(gpio3)
|
||||
ATTR(gpio4)
|
||||
ATTR(gpio5)
|
||||
ATTR(gpio6)
|
||||
ATTR(gpio7)
|
||||
ATTR(timer) /* TOYMATCH2-based wakeup enable */
|
||||
ATTR(timer_timeout) /* timer-based wakeup timeout value, in seconds */
|
||||
ATTR(wakesrc) /* contents of SYS_WAKESRC after last wakeup */
|
||||
ATTR(wakemsk) /* direct access to SYS_WAKEMSK */
|
||||
|
||||
#define ATTR_LIST(x) & x ## _attribute.attr
|
||||
static struct attribute *db1x_pmattrs[] = {
|
||||
ATTR_LIST(gpio0),
|
||||
ATTR_LIST(gpio1),
|
||||
ATTR_LIST(gpio2),
|
||||
ATTR_LIST(gpio3),
|
||||
ATTR_LIST(gpio4),
|
||||
ATTR_LIST(gpio5),
|
||||
ATTR_LIST(gpio6),
|
||||
ATTR_LIST(gpio7),
|
||||
ATTR_LIST(timer),
|
||||
ATTR_LIST(timer_timeout),
|
||||
ATTR_LIST(wakesrc),
|
||||
ATTR_LIST(wakemsk),
|
||||
NULL, /* terminator */
|
||||
};
|
||||
|
||||
static struct attribute_group db1x_pmattr_group = {
|
||||
.name = "db1x",
|
||||
.attrs = db1x_pmattrs,
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize suspend interface
|
||||
*/
|
||||
static int __init pm_init(void)
|
||||
{
|
||||
/* init TOY to tick at 1Hz if not already done. No need to wait
|
||||
* for confirmation since there's plenty of time from here to
|
||||
* the next suspend cycle.
|
||||
*/
|
||||
if (alchemy_rdsys(AU1000_SYS_TOYTRIM) != 32767)
|
||||
alchemy_wrsys(32767, AU1000_SYS_TOYTRIM);
|
||||
|
||||
db1x_pm_last_wakesrc = alchemy_rdsys(AU1000_SYS_WAKESRC);
|
||||
|
||||
alchemy_wrsys(0, AU1000_SYS_WAKESRC);
|
||||
alchemy_wrsys(0, AU1000_SYS_WAKEMSK);
|
||||
|
||||
suspend_set_ops(&db1x_pm_ops);
|
||||
|
||||
return sysfs_create_group(power_kobj, &db1x_pmattr_group);
|
||||
}
|
||||
|
||||
late_initcall(pm_init);
|
Loading…
Add table
Add a link
Reference in a new issue