diff options
Diffstat (limited to 'arch/arm/mach-ep93xx/core.c')
| -rw-r--r-- | arch/arm/mach-ep93xx/core.c | 1205 |
1 files changed, 855 insertions, 350 deletions
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c index 91f6a07a51d..0e571f1749d 100644 --- a/arch/arm/mach-ep93xx/core.c +++ b/arch/arm/mach-ep93xx/core.c @@ -14,42 +14,42 @@ * your option) any later version. */ +#define pr_fmt(fmt) "ep93xx " KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/init.h> -#include <linux/spinlock.h> -#include <linux/sched.h> +#include <linux/platform_device.h> #include <linux/interrupt.h> -#include <linux/serial.h> -#include <linux/tty.h> -#include <linux/bitops.h> -#include <linux/serial_8250.h> -#include <linux/serial_core.h> -#include <linux/device.h> -#include <linux/mm.h> -#include <linux/time.h> +#include <linux/dma-mapping.h> +#include <linux/sys_soc.h> #include <linux/timex.h> -#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/leds.h> #include <linux/termios.h> #include <linux/amba/bus.h> #include <linux/amba/serial.h> - -#include <asm/types.h> -#include <asm/setup.h> -#include <asm/memory.h> -#include <asm/hardware.h> -#include <asm/irq.h> -#include <asm/system.h> -#include <asm/tlbflush.h> -#include <asm/pgtable.h> -#include <asm/io.h> - +#include <linux/mtd/physmap.h> +#include <linux/i2c.h> +#include <linux/i2c-gpio.h> +#include <linux/spi/spi.h> +#include <linux/export.h> +#include <linux/irqchip/arm-vic.h> +#include <linux/reboot.h> +#include <linux/usb/ohci_pdriver.h> + +#include <mach/hardware.h> +#include <linux/platform_data/video-ep93xx.h> +#include <linux/platform_data/keypad-ep93xx.h> +#include <linux/platform_data/spi-ep93xx.h> +#include <mach/gpio-ep93xx.h> + +#include <asm/mach/arch.h> #include <asm/mach/map.h> #include <asm/mach/time.h> -#include <asm/mach/irq.h> -#include <asm/arch/gpio.h> - -#include <asm/hardware/vic.h> +#include "soc.h" /************************************************************************* * Static I/O mappings that are needed for all EP93xx platforms @@ -93,13 +93,40 @@ void __init ep93xx_map_io(void) * to use this timer for something else. We also use timer 4 for keeping * track of lost jiffies. */ -static unsigned int last_jiffy_time; +#define EP93XX_TIMER_REG(x) (EP93XX_TIMER_BASE + (x)) +#define EP93XX_TIMER1_LOAD EP93XX_TIMER_REG(0x00) +#define EP93XX_TIMER1_VALUE EP93XX_TIMER_REG(0x04) +#define EP93XX_TIMER1_CONTROL EP93XX_TIMER_REG(0x08) +#define EP93XX_TIMER123_CONTROL_ENABLE (1 << 7) +#define EP93XX_TIMER123_CONTROL_MODE (1 << 6) +#define EP93XX_TIMER123_CONTROL_CLKSEL (1 << 3) +#define EP93XX_TIMER1_CLEAR EP93XX_TIMER_REG(0x0c) +#define EP93XX_TIMER2_LOAD EP93XX_TIMER_REG(0x20) +#define EP93XX_TIMER2_VALUE EP93XX_TIMER_REG(0x24) +#define EP93XX_TIMER2_CONTROL EP93XX_TIMER_REG(0x28) +#define EP93XX_TIMER2_CLEAR EP93XX_TIMER_REG(0x2c) +#define EP93XX_TIMER4_VALUE_LOW EP93XX_TIMER_REG(0x60) +#define EP93XX_TIMER4_VALUE_HIGH EP93XX_TIMER_REG(0x64) +#define EP93XX_TIMER4_VALUE_HIGH_ENABLE (1 << 8) +#define EP93XX_TIMER3_LOAD EP93XX_TIMER_REG(0x80) +#define EP93XX_TIMER3_VALUE EP93XX_TIMER_REG(0x84) +#define EP93XX_TIMER3_CONTROL EP93XX_TIMER_REG(0x88) +#define EP93XX_TIMER3_CLEAR EP93XX_TIMER_REG(0x8c) + +#define EP93XX_TIMER123_CLOCK 508469 +#define EP93XX_TIMER4_CLOCK 983040 + +#define TIMER1_RELOAD ((EP93XX_TIMER123_CLOCK / HZ) - 1) +#define TIMER4_TICKS_PER_JIFFY DIV_ROUND_CLOSEST(EP93XX_TIMER4_CLOCK, HZ) -#define TIMER4_TICKS_PER_JIFFY ((CLOCK_TICK_RATE + (HZ/2)) / HZ) +static unsigned int last_jiffy_time; -static int ep93xx_timer_interrupt(int irq, void *dev_id) +static irqreturn_t ep93xx_timer_interrupt(int irq, void *dev_id) { + /* Writing any value clears the timer interrupt */ __raw_writel(1, EP93XX_TIMER1_CLEAR); + + /* Recover lost jiffies */ while ((signed long) (__raw_readl(EP93XX_TIMER4_VALUE_LOW) - last_jiffy_time) >= TIMER4_TICKS_PER_JIFFY) { @@ -112,455 +139,911 @@ static int ep93xx_timer_interrupt(int irq, void *dev_id) static struct irqaction ep93xx_timer_irq = { .name = "ep93xx timer", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .flags = IRQF_TIMER | IRQF_IRQPOLL, .handler = ep93xx_timer_interrupt, }; -static void __init ep93xx_timer_init(void) +static u32 ep93xx_gettimeoffset(void) +{ + int offset; + + offset = __raw_readl(EP93XX_TIMER4_VALUE_LOW) - last_jiffy_time; + + /* + * Timer 4 is based on a 983.04 kHz reference clock, + * so dividing by 983040 gives the fraction of a second, + * so dividing by 0.983040 converts to uS. + * Refactor the calculation to avoid overflow. + * Finally, multiply by 1000 to give nS. + */ + return (offset + (53 * offset / 3072)) * 1000; +} + +void __init ep93xx_timer_init(void) { + u32 tmode = EP93XX_TIMER123_CONTROL_MODE | + EP93XX_TIMER123_CONTROL_CLKSEL; + + arch_gettimeoffset = ep93xx_gettimeoffset; + /* Enable periodic HZ timer. */ - __raw_writel(0x48, EP93XX_TIMER1_CONTROL); - __raw_writel((508469 / HZ) - 1, EP93XX_TIMER1_LOAD); - __raw_writel(0xc8, EP93XX_TIMER1_CONTROL); + __raw_writel(tmode, EP93XX_TIMER1_CONTROL); + __raw_writel(TIMER1_RELOAD, EP93XX_TIMER1_LOAD); + __raw_writel(tmode | EP93XX_TIMER123_CONTROL_ENABLE, + EP93XX_TIMER1_CONTROL); /* Enable lost jiffy timer. */ - __raw_writel(0x100, EP93XX_TIMER4_VALUE_HIGH); + __raw_writel(EP93XX_TIMER4_VALUE_HIGH_ENABLE, + EP93XX_TIMER4_VALUE_HIGH); setup_irq(IRQ_EP93XX_TIMER1, &ep93xx_timer_irq); } -static unsigned long ep93xx_gettimeoffset(void) + +/************************************************************************* + * EP93xx IRQ handling + *************************************************************************/ +void __init ep93xx_init_irq(void) { - int offset; + vic_init(EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK, 0); + vic_init(EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK, 0); +} - offset = __raw_readl(EP93XX_TIMER4_VALUE_LOW) - last_jiffy_time; - /* Calculate (1000000 / 983040) * offset. */ - return offset + (53 * offset / 3072); +/************************************************************************* + * EP93xx System Controller Software Locked register handling + *************************************************************************/ + +/* + * syscon_swlock prevents anything else from writing to the syscon + * block while a software locked register is being written. + */ +static DEFINE_SPINLOCK(syscon_swlock); + +void ep93xx_syscon_swlocked_write(unsigned int val, void __iomem *reg) +{ + unsigned long flags; + + spin_lock_irqsave(&syscon_swlock, flags); + + __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK); + __raw_writel(val, reg); + + spin_unlock_irqrestore(&syscon_swlock, flags); } -struct sys_timer ep93xx_timer = { - .init = ep93xx_timer_init, - .offset = ep93xx_gettimeoffset, -}; +void ep93xx_devcfg_set_clear(unsigned int set_bits, unsigned int clear_bits) +{ + unsigned long flags; + unsigned int val; + spin_lock_irqsave(&syscon_swlock, flags); + + val = __raw_readl(EP93XX_SYSCON_DEVCFG); + val &= ~clear_bits; + val |= set_bits; + __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK); + __raw_writel(val, EP93XX_SYSCON_DEVCFG); + + spin_unlock_irqrestore(&syscon_swlock, flags); +} + +/** + * ep93xx_chip_revision() - returns the EP93xx chip revision + * + * See <mach/platform.h> for more information. + */ +unsigned int ep93xx_chip_revision(void) +{ + unsigned int v; + + v = __raw_readl(EP93XX_SYSCON_SYSCFG); + v &= EP93XX_SYSCON_SYSCFG_REV_MASK; + v >>= EP93XX_SYSCON_SYSCFG_REV_SHIFT; + return v; +} +EXPORT_SYMBOL_GPL(ep93xx_chip_revision); /************************************************************************* - * GPIO handling for EP93xx + * EP93xx GPIO *************************************************************************/ -static unsigned char gpio_int_unmasked[3]; -static unsigned char gpio_int_enabled[3]; -static unsigned char gpio_int_type1[3]; -static unsigned char gpio_int_type2[3]; +static struct resource ep93xx_gpio_resource[] = { + DEFINE_RES_MEM(EP93XX_GPIO_PHYS_BASE, 0xcc), +}; -/* Port ordering is: A B F */ -static const u8 int_type1_register_offset[3] = { 0x90, 0xac, 0x4c }; -static const u8 int_type2_register_offset[3] = { 0x94, 0xb0, 0x50 }; -static const u8 eoi_register_offset[3] = { 0x98, 0xb4, 0x54 }; -static const u8 int_en_register_offset[3] = { 0x9c, 0xb8, 0x5c }; +static struct platform_device ep93xx_gpio_device = { + .name = "gpio-ep93xx", + .id = -1, + .num_resources = ARRAY_SIZE(ep93xx_gpio_resource), + .resource = ep93xx_gpio_resource, +}; + +/************************************************************************* + * EP93xx peripheral handling + *************************************************************************/ +#define EP93XX_UART_MCR_OFFSET (0x0100) -static void update_gpio_int_params(unsigned port) +static void ep93xx_uart_set_mctrl(struct amba_device *dev, + void __iomem *base, unsigned int mctrl) { - BUG_ON(port > 2); + unsigned int mcr; + + mcr = 0; + if (mctrl & TIOCM_RTS) + mcr |= 2; + if (mctrl & TIOCM_DTR) + mcr |= 1; - __raw_writeb(0, EP93XX_GPIO_REG(int_en_register_offset[port])); + __raw_writel(mcr, base + EP93XX_UART_MCR_OFFSET); +} - __raw_writeb(gpio_int_type2[port], - EP93XX_GPIO_REG(int_type2_register_offset[port])); +static struct amba_pl010_data ep93xx_uart_data = { + .set_mctrl = ep93xx_uart_set_mctrl, +}; - __raw_writeb(gpio_int_type1[port], - EP93XX_GPIO_REG(int_type1_register_offset[port])); +static AMBA_APB_DEVICE(uart1, "apb:uart1", 0x00041010, EP93XX_UART1_PHYS_BASE, + { IRQ_EP93XX_UART1 }, &ep93xx_uart_data); - __raw_writeb(gpio_int_unmasked[port] & gpio_int_enabled[port], - EP93XX_GPIO_REG(int_en_register_offset[port])); -} +static AMBA_APB_DEVICE(uart2, "apb:uart2", 0x00041010, EP93XX_UART2_PHYS_BASE, + { IRQ_EP93XX_UART2 }, NULL); -/* Port ordering is: A B F D E C G H */ -static const u8 data_register_offset[8] = { - 0x00, 0x04, 0x30, 0x0c, 0x20, 0x08, 0x38, 0x40, +static AMBA_APB_DEVICE(uart3, "apb:uart3", 0x00041010, EP93XX_UART3_PHYS_BASE, + { IRQ_EP93XX_UART3 }, &ep93xx_uart_data); + +static struct resource ep93xx_rtc_resource[] = { + DEFINE_RES_MEM(EP93XX_RTC_PHYS_BASE, 0x10c), }; -static const u8 data_direction_register_offset[8] = { - 0x10, 0x14, 0x34, 0x1c, 0x24, 0x18, 0x3c, 0x44, +static struct platform_device ep93xx_rtc_device = { + .name = "ep93xx-rtc", + .id = -1, + .num_resources = ARRAY_SIZE(ep93xx_rtc_resource), + .resource = ep93xx_rtc_resource, }; -#define GPIO_IN 0 -#define GPIO_OUT 1 +/************************************************************************* + * EP93xx OHCI USB Host + *************************************************************************/ -static void ep93xx_gpio_set_direction(unsigned line, int direction) +static struct clk *ep93xx_ohci_host_clock; + +static int ep93xx_ohci_power_on(struct platform_device *pdev) { - unsigned int data_direction_register; - unsigned long flags; - unsigned char v; - - data_direction_register = - EP93XX_GPIO_REG(data_direction_register_offset[line >> 3]); - - local_irq_save(flags); - if (direction == GPIO_OUT) { - if (line >= 0 && line <= EP93XX_GPIO_LINE_MAX_IRQ) { - /* Port A/B/F */ - gpio_int_unmasked[line >> 3] &= ~(1 << (line & 7)); - update_gpio_int_params(line >> 3); - } - - v = __raw_readb(data_direction_register); - v |= 1 << (line & 7); - __raw_writeb(v, data_direction_register); - } else if (direction == GPIO_IN) { - v = __raw_readb(data_direction_register); - v &= ~(1 << (line & 7)); - __raw_writeb(v, data_direction_register); + if (!ep93xx_ohci_host_clock) { + ep93xx_ohci_host_clock = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(ep93xx_ohci_host_clock)) + return PTR_ERR(ep93xx_ohci_host_clock); } - local_irq_restore(flags); + + return clk_enable(ep93xx_ohci_host_clock); } -int gpio_direction_input(unsigned gpio) +static void ep93xx_ohci_power_off(struct platform_device *pdev) { - if (gpio > EP93XX_GPIO_LINE_MAX) - return -EINVAL; + clk_disable(ep93xx_ohci_host_clock); +} - ep93xx_gpio_set_direction(gpio, GPIO_IN); +static struct usb_ohci_pdata ep93xx_ohci_pdata = { + .power_on = ep93xx_ohci_power_on, + .power_off = ep93xx_ohci_power_off, + .power_suspend = ep93xx_ohci_power_off, +}; - return 0; -} -EXPORT_SYMBOL(gpio_direction_input); +static struct resource ep93xx_ohci_resources[] = { + DEFINE_RES_MEM(EP93XX_USB_PHYS_BASE, 0x1000), + DEFINE_RES_IRQ(IRQ_EP93XX_USB), +}; -int gpio_direction_output(unsigned gpio, int value) -{ - if (gpio > EP93XX_GPIO_LINE_MAX) - return -EINVAL; +static u64 ep93xx_ohci_dma_mask = DMA_BIT_MASK(32); - gpio_set_value(gpio, value); - ep93xx_gpio_set_direction(gpio, GPIO_OUT); +static struct platform_device ep93xx_ohci_device = { + .name = "ohci-platform", + .id = -1, + .num_resources = ARRAY_SIZE(ep93xx_ohci_resources), + .resource = ep93xx_ohci_resources, + .dev = { + .dma_mask = &ep93xx_ohci_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &ep93xx_ohci_pdata, + }, +}; - return 0; -} -EXPORT_SYMBOL(gpio_direction_output); +/************************************************************************* + * EP93xx physmap'ed flash + *************************************************************************/ +static struct physmap_flash_data ep93xx_flash_data; + +static struct resource ep93xx_flash_resource = { + .flags = IORESOURCE_MEM, +}; -int gpio_get_value(unsigned gpio) +static struct platform_device ep93xx_flash = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &ep93xx_flash_data, + }, + .num_resources = 1, + .resource = &ep93xx_flash_resource, +}; + +/** + * ep93xx_register_flash() - Register the external flash device. + * @width: bank width in octets + * @start: resource start address + * @size: resource size + */ +void __init ep93xx_register_flash(unsigned int width, + resource_size_t start, resource_size_t size) { - unsigned int data_register; + ep93xx_flash_data.width = width; - data_register = EP93XX_GPIO_REG(data_register_offset[gpio >> 3]); + ep93xx_flash_resource.start = start; + ep93xx_flash_resource.end = start + size - 1; - return !!(__raw_readb(data_register) & (1 << (gpio & 7))); + platform_device_register(&ep93xx_flash); } -EXPORT_SYMBOL(gpio_get_value); -void gpio_set_value(unsigned gpio, int value) -{ - unsigned int data_register; - unsigned long flags; - unsigned char v; - data_register = EP93XX_GPIO_REG(data_register_offset[gpio >> 3]); +/************************************************************************* + * EP93xx ethernet peripheral handling + *************************************************************************/ +static struct ep93xx_eth_data ep93xx_eth_data; + +static struct resource ep93xx_eth_resource[] = { + DEFINE_RES_MEM(EP93XX_ETHERNET_PHYS_BASE, 0x10000), + DEFINE_RES_IRQ(IRQ_EP93XX_ETHERNET), +}; - local_irq_save(flags); - v = __raw_readb(data_register); - if (value) - v |= 1 << (gpio & 7); - else - v &= ~(1 << (gpio & 7)); - __raw_writeb(v, data_register); - local_irq_restore(flags); +static u64 ep93xx_eth_dma_mask = DMA_BIT_MASK(32); + +static struct platform_device ep93xx_eth_device = { + .name = "ep93xx-eth", + .id = -1, + .dev = { + .platform_data = &ep93xx_eth_data, + .coherent_dma_mask = DMA_BIT_MASK(32), + .dma_mask = &ep93xx_eth_dma_mask, + }, + .num_resources = ARRAY_SIZE(ep93xx_eth_resource), + .resource = ep93xx_eth_resource, +}; + +/** + * ep93xx_register_eth - Register the built-in ethernet platform device. + * @data: platform specific ethernet configuration (__initdata) + * @copy_addr: flag indicating that the MAC address should be copied + * from the IndAd registers (as programmed by the bootloader) + */ +void __init ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr) +{ + if (copy_addr) + memcpy_fromio(data->dev_addr, EP93XX_ETHERNET_BASE + 0x50, 6); + + ep93xx_eth_data = *data; + platform_device_register(&ep93xx_eth_device); } -EXPORT_SYMBOL(gpio_set_value); /************************************************************************* - * EP93xx IRQ handling + * EP93xx i2c peripheral handling *************************************************************************/ -static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc) -{ - unsigned char status; - int i; +static struct i2c_gpio_platform_data ep93xx_i2c_data; - status = __raw_readb(EP93XX_GPIO_A_INT_STATUS); - for (i = 0; i < 8; i++) { - if (status & (1 << i)) { - int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_A(0)) + i; - desc = irq_desc + gpio_irq; - desc_handle_irq(gpio_irq, desc); - } - } +static struct platform_device ep93xx_i2c_device = { + .name = "i2c-gpio", + .id = 0, + .dev = { + .platform_data = &ep93xx_i2c_data, + }, +}; - status = __raw_readb(EP93XX_GPIO_B_INT_STATUS); - for (i = 0; i < 8; i++) { - if (status & (1 << i)) { - int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_B(0)) + i; - desc = irq_desc + gpio_irq; - desc_handle_irq(gpio_irq, desc); - } - } +/** + * ep93xx_register_i2c - Register the i2c platform device. + * @data: platform specific i2c-gpio configuration (__initdata) + * @devices: platform specific i2c bus device information (__initdata) + * @num: the number of devices on the i2c bus + */ +void __init ep93xx_register_i2c(struct i2c_gpio_platform_data *data, + struct i2c_board_info *devices, int num) +{ + /* + * Set the EEPROM interface pin drive type control. + * Defines the driver type for the EECLK and EEDAT pins as either + * open drain, which will require an external pull-up, or a normal + * CMOS driver. + */ + if (data->sda_is_open_drain && data->sda_pin != EP93XX_GPIO_LINE_EEDAT) + pr_warning("sda != EEDAT, open drain has no effect\n"); + if (data->scl_is_open_drain && data->scl_pin != EP93XX_GPIO_LINE_EECLK) + pr_warning("scl != EECLK, open drain has no effect\n"); + + __raw_writel((data->sda_is_open_drain << 1) | + (data->scl_is_open_drain << 0), + EP93XX_GPIO_EEDRIVE); + + ep93xx_i2c_data = *data; + i2c_register_board_info(0, devices, num); + platform_device_register(&ep93xx_i2c_device); } -static void ep93xx_gpio_f_irq_handler(unsigned int irq, struct irq_desc *desc) +/************************************************************************* + * EP93xx SPI peripheral handling + *************************************************************************/ +static struct ep93xx_spi_info ep93xx_spi_master_data; + +static struct resource ep93xx_spi_resources[] = { + DEFINE_RES_MEM(EP93XX_SPI_PHYS_BASE, 0x18), + DEFINE_RES_IRQ(IRQ_EP93XX_SSP), +}; + +static u64 ep93xx_spi_dma_mask = DMA_BIT_MASK(32); + +static struct platform_device ep93xx_spi_device = { + .name = "ep93xx-spi", + .id = 0, + .dev = { + .platform_data = &ep93xx_spi_master_data, + .coherent_dma_mask = DMA_BIT_MASK(32), + .dma_mask = &ep93xx_spi_dma_mask, + }, + .num_resources = ARRAY_SIZE(ep93xx_spi_resources), + .resource = ep93xx_spi_resources, +}; + +/** + * ep93xx_register_spi() - registers spi platform device + * @info: ep93xx board specific spi master info (__initdata) + * @devices: SPI devices to register (__initdata) + * @num: number of SPI devices to register + * + * This function registers platform device for the EP93xx SPI controller and + * also makes sure that SPI pins are muxed so that I2S is not using those pins. + */ +void __init ep93xx_register_spi(struct ep93xx_spi_info *info, + struct spi_board_info *devices, int num) { /* - * map discontiguous hw irq range to continous sw irq range: - * - * IRQ_EP93XX_GPIO{0..7}MUX -> gpio_to_irq(EP93XX_GPIO_LINE_F({0..7}) + * When SPI is used, we need to make sure that I2S is muxed off from + * SPI pins. */ - int port_f_idx = ((irq + 1) & 7) ^ 4; /* {19..22,47..50} -> {0..7} */ - int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_F(0)) + port_f_idx; + ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2SONSSP); - desc_handle_irq(gpio_irq, irq_desc + gpio_irq); + ep93xx_spi_master_data = *info; + spi_register_board_info(devices, num); + platform_device_register(&ep93xx_spi_device); } -static void ep93xx_gpio_irq_ack(unsigned int irq) -{ - int line = irq_to_gpio(irq); - int port = line >> 3; - int port_mask = 1 << (line & 7); +/************************************************************************* + * EP93xx LEDs + *************************************************************************/ +static const struct gpio_led ep93xx_led_pins[] __initconst = { + { + .name = "platform:grled", + .gpio = EP93XX_GPIO_LINE_GRLED, + }, { + .name = "platform:rdled", + .gpio = EP93XX_GPIO_LINE_RDLED, + }, +}; - if ((irq_desc[irq].status & IRQ_TYPE_SENSE_MASK) == IRQT_BOTHEDGE) { - gpio_int_type2[port] ^= port_mask; /* switch edge direction */ - update_gpio_int_params(port); - } +static const struct gpio_led_platform_data ep93xx_led_data __initconst = { + .num_leds = ARRAY_SIZE(ep93xx_led_pins), + .leds = ep93xx_led_pins, +}; - __raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); -} +/************************************************************************* + * EP93xx pwm peripheral handling + *************************************************************************/ +static struct resource ep93xx_pwm0_resource[] = { + DEFINE_RES_MEM(EP93XX_PWM_PHYS_BASE, 0x10), +}; -static void ep93xx_gpio_irq_mask_ack(unsigned int irq) -{ - int line = irq_to_gpio(irq); - int port = line >> 3; - int port_mask = 1 << (line & 7); +static struct platform_device ep93xx_pwm0_device = { + .name = "ep93xx-pwm", + .id = 0, + .num_resources = ARRAY_SIZE(ep93xx_pwm0_resource), + .resource = ep93xx_pwm0_resource, +}; + +static struct resource ep93xx_pwm1_resource[] = { + DEFINE_RES_MEM(EP93XX_PWM_PHYS_BASE + 0x20, 0x10), +}; - if ((irq_desc[irq].status & IRQ_TYPE_SENSE_MASK) == IRQT_BOTHEDGE) - gpio_int_type2[port] ^= port_mask; /* switch edge direction */ +static struct platform_device ep93xx_pwm1_device = { + .name = "ep93xx-pwm", + .id = 1, + .num_resources = ARRAY_SIZE(ep93xx_pwm1_resource), + .resource = ep93xx_pwm1_resource, +}; - gpio_int_unmasked[port] &= ~port_mask; - update_gpio_int_params(port); +void __init ep93xx_register_pwm(int pwm0, int pwm1) +{ + if (pwm0) + platform_device_register(&ep93xx_pwm0_device); - __raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); + /* NOTE: EP9307 does not have PWMOUT1 (pin EGPIO14) */ + if (pwm1) + platform_device_register(&ep93xx_pwm1_device); } -static void ep93xx_gpio_irq_mask(unsigned int irq) +int ep93xx_pwm_acquire_gpio(struct platform_device *pdev) { - int line = irq_to_gpio(irq); - int port = line >> 3; + int err; + + if (pdev->id == 0) { + err = 0; + } else if (pdev->id == 1) { + err = gpio_request(EP93XX_GPIO_LINE_EGPIO14, + dev_name(&pdev->dev)); + if (err) + return err; + err = gpio_direction_output(EP93XX_GPIO_LINE_EGPIO14, 0); + if (err) + goto fail; + + /* PWM 1 output on EGPIO[14] */ + ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_PONG); + } else { + err = -ENODEV; + } - gpio_int_unmasked[port] &= ~(1 << (line & 7)); - update_gpio_int_params(port); + return err; + +fail: + gpio_free(EP93XX_GPIO_LINE_EGPIO14); + return err; } +EXPORT_SYMBOL(ep93xx_pwm_acquire_gpio); -static void ep93xx_gpio_irq_unmask(unsigned int irq) +void ep93xx_pwm_release_gpio(struct platform_device *pdev) { - int line = irq_to_gpio(irq); - int port = line >> 3; + if (pdev->id == 1) { + gpio_direction_input(EP93XX_GPIO_LINE_EGPIO14); + gpio_free(EP93XX_GPIO_LINE_EGPIO14); - gpio_int_unmasked[port] |= 1 << (line & 7); - update_gpio_int_params(port); + /* EGPIO[14] used for GPIO */ + ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_PONG); + } } +EXPORT_SYMBOL(ep93xx_pwm_release_gpio); -/* - * gpio_int_type1 controls whether the interrupt is level (0) or - * edge (1) triggered, while gpio_int_type2 controls whether it - * triggers on low/falling (0) or high/rising (1). - */ -static int ep93xx_gpio_irq_type(unsigned int irq, unsigned int type) -{ - struct irq_desc *desc = irq_desc + irq; - const int gpio = irq_to_gpio(irq); - const int port = gpio >> 3; - const int port_mask = 1 << (gpio & 7); - - ep93xx_gpio_set_direction(gpio, GPIO_IN); - - switch (type) { - case IRQT_RISING: - gpio_int_type1[port] |= port_mask; - gpio_int_type2[port] |= port_mask; - desc->handle_irq = handle_edge_irq; - break; - case IRQT_FALLING: - gpio_int_type1[port] |= port_mask; - gpio_int_type2[port] &= ~port_mask; - desc->handle_irq = handle_edge_irq; - break; - case IRQT_HIGH: - gpio_int_type1[port] &= ~port_mask; - gpio_int_type2[port] |= port_mask; - desc->handle_irq = handle_level_irq; - break; - case IRQT_LOW: - gpio_int_type1[port] &= ~port_mask; - gpio_int_type2[port] &= ~port_mask; - desc->handle_irq = handle_level_irq; - break; - case IRQT_BOTHEDGE: - gpio_int_type1[port] |= port_mask; - /* set initial polarity based on current input level */ - if (gpio_get_value(gpio)) - gpio_int_type2[port] &= ~port_mask; /* falling */ - else - gpio_int_type2[port] |= port_mask; /* rising */ - desc->handle_irq = handle_edge_irq; - break; - default: - pr_err("ep93xx: failed to set irq type %d for gpio %d\n", - type, gpio); - return -EINVAL; - } +/************************************************************************* + * EP93xx video peripheral handling + *************************************************************************/ +static struct ep93xxfb_mach_info ep93xxfb_data; - gpio_int_enabled[port] |= port_mask; +static struct resource ep93xx_fb_resource[] = { + DEFINE_RES_MEM(EP93XX_RASTER_PHYS_BASE, 0x800), +}; - desc->status &= ~IRQ_TYPE_SENSE_MASK; - desc->status |= type & IRQ_TYPE_SENSE_MASK; +static struct platform_device ep93xx_fb_device = { + .name = "ep93xx-fb", + .id = -1, + .dev = { + .platform_data = &ep93xxfb_data, + .coherent_dma_mask = DMA_BIT_MASK(32), + .dma_mask = &ep93xx_fb_device.dev.coherent_dma_mask, + }, + .num_resources = ARRAY_SIZE(ep93xx_fb_resource), + .resource = ep93xx_fb_resource, +}; - update_gpio_int_params(port); +/* The backlight use a single register in the framebuffer's register space */ +#define EP93XX_RASTER_REG_BRIGHTNESS 0x20 - return 0; +static struct resource ep93xx_bl_resources[] = { + DEFINE_RES_MEM(EP93XX_RASTER_PHYS_BASE + + EP93XX_RASTER_REG_BRIGHTNESS, 0x04), +}; + +static struct platform_device ep93xx_bl_device = { + .name = "ep93xx-bl", + .id = -1, + .num_resources = ARRAY_SIZE(ep93xx_bl_resources), + .resource = ep93xx_bl_resources, +}; + +/** + * ep93xx_register_fb - Register the framebuffer platform device. + * @data: platform specific framebuffer configuration (__initdata) + */ +void __init ep93xx_register_fb(struct ep93xxfb_mach_info *data) +{ + ep93xxfb_data = *data; + platform_device_register(&ep93xx_fb_device); + platform_device_register(&ep93xx_bl_device); } -static struct irq_chip ep93xx_gpio_irq_chip = { - .name = "GPIO", - .ack = ep93xx_gpio_irq_ack, - .mask_ack = ep93xx_gpio_irq_mask_ack, - .mask = ep93xx_gpio_irq_mask, - .unmask = ep93xx_gpio_irq_unmask, - .set_type = ep93xx_gpio_irq_type, + +/************************************************************************* + * EP93xx matrix keypad peripheral handling + *************************************************************************/ +static struct ep93xx_keypad_platform_data ep93xx_keypad_data; + +static struct resource ep93xx_keypad_resource[] = { + DEFINE_RES_MEM(EP93XX_KEY_MATRIX_PHYS_BASE, 0x0c), + DEFINE_RES_IRQ(IRQ_EP93XX_KEY), }; +static struct platform_device ep93xx_keypad_device = { + .name = "ep93xx-keypad", + .id = -1, + .dev = { + .platform_data = &ep93xx_keypad_data, + }, + .num_resources = ARRAY_SIZE(ep93xx_keypad_resource), + .resource = ep93xx_keypad_resource, +}; -void __init ep93xx_init_irq(void) +/** + * ep93xx_register_keypad - Register the keypad platform device. + * @data: platform specific keypad configuration (__initdata) + */ +void __init ep93xx_register_keypad(struct ep93xx_keypad_platform_data *data) { - int gpio_irq; + ep93xx_keypad_data = *data; + platform_device_register(&ep93xx_keypad_device); +} - vic_init((void *)EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK); - vic_init((void *)EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK); +int ep93xx_keypad_acquire_gpio(struct platform_device *pdev) +{ + int err; + int i; - for (gpio_irq = gpio_to_irq(0); - gpio_irq <= gpio_to_irq(EP93XX_GPIO_LINE_MAX_IRQ); ++gpio_irq) { - set_irq_chip(gpio_irq, &ep93xx_gpio_irq_chip); - set_irq_handler(gpio_irq, handle_level_irq); - set_irq_flags(gpio_irq, IRQF_VALID); + for (i = 0; i < 8; i++) { + err = gpio_request(EP93XX_GPIO_LINE_C(i), dev_name(&pdev->dev)); + if (err) + goto fail_gpio_c; + err = gpio_request(EP93XX_GPIO_LINE_D(i), dev_name(&pdev->dev)); + if (err) + goto fail_gpio_d; } - set_irq_chained_handler(IRQ_EP93XX_GPIO_AB, ep93xx_gpio_ab_irq_handler); - set_irq_chained_handler(IRQ_EP93XX_GPIO0MUX, ep93xx_gpio_f_irq_handler); - set_irq_chained_handler(IRQ_EP93XX_GPIO1MUX, ep93xx_gpio_f_irq_handler); - set_irq_chained_handler(IRQ_EP93XX_GPIO2MUX, ep93xx_gpio_f_irq_handler); - set_irq_chained_handler(IRQ_EP93XX_GPIO3MUX, ep93xx_gpio_f_irq_handler); - set_irq_chained_handler(IRQ_EP93XX_GPIO4MUX, ep93xx_gpio_f_irq_handler); - set_irq_chained_handler(IRQ_EP93XX_GPIO5MUX, ep93xx_gpio_f_irq_handler); - set_irq_chained_handler(IRQ_EP93XX_GPIO6MUX, ep93xx_gpio_f_irq_handler); - set_irq_chained_handler(IRQ_EP93XX_GPIO7MUX, ep93xx_gpio_f_irq_handler); + /* Enable the keypad controller; GPIO ports C and D used for keypad */ + ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_KEYS | + EP93XX_SYSCON_DEVCFG_GONK); + + return 0; + +fail_gpio_d: + gpio_free(EP93XX_GPIO_LINE_C(i)); +fail_gpio_c: + for (--i; i >= 0; --i) { + gpio_free(EP93XX_GPIO_LINE_C(i)); + gpio_free(EP93XX_GPIO_LINE_D(i)); + } + return err; } +EXPORT_SYMBOL(ep93xx_keypad_acquire_gpio); + +void ep93xx_keypad_release_gpio(struct platform_device *pdev) +{ + int i; + for (i = 0; i < 8; i++) { + gpio_free(EP93XX_GPIO_LINE_C(i)); + gpio_free(EP93XX_GPIO_LINE_D(i)); + } + + /* Disable the keypad controller; GPIO ports C and D used for GPIO */ + ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_KEYS | + EP93XX_SYSCON_DEVCFG_GONK); +} +EXPORT_SYMBOL(ep93xx_keypad_release_gpio); /************************************************************************* - * EP93xx peripheral handling + * EP93xx I2S audio peripheral handling *************************************************************************/ -#define EP93XX_UART_MCR_OFFSET (0x0100) +static struct resource ep93xx_i2s_resource[] = { + DEFINE_RES_MEM(EP93XX_I2S_PHYS_BASE, 0x100), +}; -static void ep93xx_uart_set_mctrl(struct amba_device *dev, - void __iomem *base, unsigned int mctrl) +static struct platform_device ep93xx_i2s_device = { + .name = "ep93xx-i2s", + .id = -1, + .num_resources = ARRAY_SIZE(ep93xx_i2s_resource), + .resource = ep93xx_i2s_resource, +}; + +static struct platform_device ep93xx_pcm_device = { + .name = "ep93xx-pcm-audio", + .id = -1, +}; + +void __init ep93xx_register_i2s(void) { - unsigned int mcr; + platform_device_register(&ep93xx_i2s_device); + platform_device_register(&ep93xx_pcm_device); +} - mcr = 0; - if (!(mctrl & TIOCM_RTS)) - mcr |= 2; - if (!(mctrl & TIOCM_DTR)) - mcr |= 1; +#define EP93XX_SYSCON_DEVCFG_I2S_MASK (EP93XX_SYSCON_DEVCFG_I2SONSSP | \ + EP93XX_SYSCON_DEVCFG_I2SONAC97) - __raw_writel(mcr, base + EP93XX_UART_MCR_OFFSET); +#define EP93XX_I2SCLKDIV_MASK (EP93XX_SYSCON_I2SCLKDIV_ORIDE | \ + EP93XX_SYSCON_I2SCLKDIV_SPOL) + +int ep93xx_i2s_acquire(void) +{ + unsigned val; + + ep93xx_devcfg_set_clear(EP93XX_SYSCON_DEVCFG_I2SONAC97, + EP93XX_SYSCON_DEVCFG_I2S_MASK); + + /* + * This is potentially racy with the clock api for i2s_mclk, sclk and + * lrclk. Since the i2s driver is the only user of those clocks we + * rely on it to prevent parallel use of this function and the + * clock api for the i2s clocks. + */ + val = __raw_readl(EP93XX_SYSCON_I2SCLKDIV); + val &= ~EP93XX_I2SCLKDIV_MASK; + val |= EP93XX_SYSCON_I2SCLKDIV_ORIDE | EP93XX_SYSCON_I2SCLKDIV_SPOL; + ep93xx_syscon_swlocked_write(val, EP93XX_SYSCON_I2SCLKDIV); + + return 0; } +EXPORT_SYMBOL(ep93xx_i2s_acquire); -static struct amba_pl010_data ep93xx_uart_data = { - .set_mctrl = ep93xx_uart_set_mctrl, -}; +void ep93xx_i2s_release(void) +{ + ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2S_MASK); +} +EXPORT_SYMBOL(ep93xx_i2s_release); -static struct amba_device uart1_device = { - .dev = { - .bus_id = "apb:uart1", - .platform_data = &ep93xx_uart_data, - }, - .res = { - .start = EP93XX_UART1_PHYS_BASE, - .end = EP93XX_UART1_PHYS_BASE + 0x0fff, - .flags = IORESOURCE_MEM, - }, - .irq = { IRQ_EP93XX_UART1, NO_IRQ }, - .periphid = 0x00041010, +/************************************************************************* + * EP93xx AC97 audio peripheral handling + *************************************************************************/ +static struct resource ep93xx_ac97_resources[] = { + DEFINE_RES_MEM(EP93XX_AAC_PHYS_BASE, 0xac), + DEFINE_RES_IRQ(IRQ_EP93XX_AACINTR), }; -static struct amba_device uart2_device = { - .dev = { - .bus_id = "apb:uart2", - .platform_data = &ep93xx_uart_data, - }, - .res = { - .start = EP93XX_UART2_PHYS_BASE, - .end = EP93XX_UART2_PHYS_BASE + 0x0fff, - .flags = IORESOURCE_MEM, - }, - .irq = { IRQ_EP93XX_UART2, NO_IRQ }, - .periphid = 0x00041010, +static struct platform_device ep93xx_ac97_device = { + .name = "ep93xx-ac97", + .id = -1, + .num_resources = ARRAY_SIZE(ep93xx_ac97_resources), + .resource = ep93xx_ac97_resources, }; -static struct amba_device uart3_device = { - .dev = { - .bus_id = "apb:uart3", - .platform_data = &ep93xx_uart_data, - }, - .res = { - .start = EP93XX_UART3_PHYS_BASE, - .end = EP93XX_UART3_PHYS_BASE + 0x0fff, - .flags = IORESOURCE_MEM, - }, - .irq = { IRQ_EP93XX_UART3, NO_IRQ }, - .periphid = 0x00041010, -}; +void __init ep93xx_register_ac97(void) +{ + /* + * Make sure that the AC97 pins are not used by I2S. + */ + ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2SONAC97); + platform_device_register(&ep93xx_ac97_device); + platform_device_register(&ep93xx_pcm_device); +} -static struct platform_device ep93xx_rtc_device = { - .name = "ep93xx-rtc", - .id = -1, - .num_resources = 0, +/************************************************************************* + * EP93xx Watchdog + *************************************************************************/ +static struct resource ep93xx_wdt_resources[] = { + DEFINE_RES_MEM(EP93XX_WATCHDOG_PHYS_BASE, 0x08), }; +static struct platform_device ep93xx_wdt_device = { + .name = "ep93xx-wdt", + .id = -1, + .num_resources = ARRAY_SIZE(ep93xx_wdt_resources), + .resource = ep93xx_wdt_resources, +}; -static struct resource ep93xx_ohci_resources[] = { - [0] = { - .start = EP93XX_USB_PHYS_BASE, - .end = EP93XX_USB_PHYS_BASE + 0x0fff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_EP93XX_USB, - .end = IRQ_EP93XX_USB, - .flags = IORESOURCE_IRQ, - }, +/************************************************************************* + * EP93xx IDE + *************************************************************************/ +static struct resource ep93xx_ide_resources[] = { + DEFINE_RES_MEM(EP93XX_IDE_PHYS_BASE, 0x38), + DEFINE_RES_IRQ(IRQ_EP93XX_EXT3), }; -static struct platform_device ep93xx_ohci_device = { - .name = "ep93xx-ohci", +static struct platform_device ep93xx_ide_device = { + .name = "ep93xx-ide", .id = -1, .dev = { - .dma_mask = (void *)0xffffffff, - .coherent_dma_mask = 0xffffffff, + .dma_mask = &ep93xx_ide_device.dev.coherent_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), }, - .num_resources = ARRAY_SIZE(ep93xx_ohci_resources), - .resource = ep93xx_ohci_resources, + .num_resources = ARRAY_SIZE(ep93xx_ide_resources), + .resource = ep93xx_ide_resources, }; +void __init ep93xx_register_ide(void) +{ + platform_device_register(&ep93xx_ide_device); +} -void __init ep93xx_init_devices(void) +int ep93xx_ide_acquire_gpio(struct platform_device *pdev) { - unsigned int v; + int err; + int i; - /* - * Disallow access to MaverickCrunch initially. - */ - v = __raw_readl(EP93XX_SYSCON_DEVICE_CONFIG); - v &= ~EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE; - __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK); - __raw_writel(v, EP93XX_SYSCON_DEVICE_CONFIG); + err = gpio_request(EP93XX_GPIO_LINE_EGPIO2, dev_name(&pdev->dev)); + if (err) + return err; + err = gpio_request(EP93XX_GPIO_LINE_EGPIO15, dev_name(&pdev->dev)); + if (err) + goto fail_egpio15; + for (i = 2; i < 8; i++) { + err = gpio_request(EP93XX_GPIO_LINE_E(i), dev_name(&pdev->dev)); + if (err) + goto fail_gpio_e; + } + for (i = 4; i < 8; i++) { + err = gpio_request(EP93XX_GPIO_LINE_G(i), dev_name(&pdev->dev)); + if (err) + goto fail_gpio_g; + } + for (i = 0; i < 8; i++) { + err = gpio_request(EP93XX_GPIO_LINE_H(i), dev_name(&pdev->dev)); + if (err) + goto fail_gpio_h; + } + + /* GPIO ports E[7:2], G[7:4] and H used by IDE */ + ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_EONIDE | + EP93XX_SYSCON_DEVCFG_GONIDE | + EP93XX_SYSCON_DEVCFG_HONIDE); + return 0; + +fail_gpio_h: + for (--i; i >= 0; --i) + gpio_free(EP93XX_GPIO_LINE_H(i)); + i = 8; +fail_gpio_g: + for (--i; i >= 4; --i) + gpio_free(EP93XX_GPIO_LINE_G(i)); + i = 8; +fail_gpio_e: + for (--i; i >= 2; --i) + gpio_free(EP93XX_GPIO_LINE_E(i)); + gpio_free(EP93XX_GPIO_LINE_EGPIO15); +fail_egpio15: + gpio_free(EP93XX_GPIO_LINE_EGPIO2); + return err; +} +EXPORT_SYMBOL(ep93xx_ide_acquire_gpio); + +void ep93xx_ide_release_gpio(struct platform_device *pdev) +{ + int i; + + for (i = 2; i < 8; i++) + gpio_free(EP93XX_GPIO_LINE_E(i)); + for (i = 4; i < 8; i++) + gpio_free(EP93XX_GPIO_LINE_G(i)); + for (i = 0; i < 8; i++) + gpio_free(EP93XX_GPIO_LINE_H(i)); + gpio_free(EP93XX_GPIO_LINE_EGPIO15); + gpio_free(EP93XX_GPIO_LINE_EGPIO2); + + + /* GPIO ports E[7:2], G[7:4] and H used by GPIO */ + ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_EONIDE | + EP93XX_SYSCON_DEVCFG_GONIDE | + EP93XX_SYSCON_DEVCFG_HONIDE); +} +EXPORT_SYMBOL(ep93xx_ide_release_gpio); + +/************************************************************************* + * EP93xx Security peripheral + *************************************************************************/ + +/* + * The Maverick Key is 256 bits of micro fuses blown at the factory during + * manufacturing to uniquely identify a part. + * + * See: http://arm.cirrus.com/forum/viewtopic.php?t=486&highlight=maverick+key + */ +#define EP93XX_SECURITY_REG(x) (EP93XX_SECURITY_BASE + (x)) +#define EP93XX_SECURITY_SECFLG EP93XX_SECURITY_REG(0x2400) +#define EP93XX_SECURITY_FUSEFLG EP93XX_SECURITY_REG(0x2410) +#define EP93XX_SECURITY_UNIQID EP93XX_SECURITY_REG(0x2440) +#define EP93XX_SECURITY_UNIQCHK EP93XX_SECURITY_REG(0x2450) +#define EP93XX_SECURITY_UNIQVAL EP93XX_SECURITY_REG(0x2460) +#define EP93XX_SECURITY_SECID1 EP93XX_SECURITY_REG(0x2500) +#define EP93XX_SECURITY_SECID2 EP93XX_SECURITY_REG(0x2504) +#define EP93XX_SECURITY_SECCHK1 EP93XX_SECURITY_REG(0x2520) +#define EP93XX_SECURITY_SECCHK2 EP93XX_SECURITY_REG(0x2524) +#define EP93XX_SECURITY_UNIQID2 EP93XX_SECURITY_REG(0x2700) +#define EP93XX_SECURITY_UNIQID3 EP93XX_SECURITY_REG(0x2704) +#define EP93XX_SECURITY_UNIQID4 EP93XX_SECURITY_REG(0x2708) +#define EP93XX_SECURITY_UNIQID5 EP93XX_SECURITY_REG(0x270c) + +static char ep93xx_soc_id[33]; + +static const char __init *ep93xx_get_soc_id(void) +{ + unsigned int id, id2, id3, id4, id5; + + if (__raw_readl(EP93XX_SECURITY_UNIQVAL) != 1) + return "bad Hamming code"; + + id = __raw_readl(EP93XX_SECURITY_UNIQID); + id2 = __raw_readl(EP93XX_SECURITY_UNIQID2); + id3 = __raw_readl(EP93XX_SECURITY_UNIQID3); + id4 = __raw_readl(EP93XX_SECURITY_UNIQID4); + id5 = __raw_readl(EP93XX_SECURITY_UNIQID5); + + if (id != id2) + return "invalid"; + + snprintf(ep93xx_soc_id, sizeof(ep93xx_soc_id), + "%08x%08x%08x%08x", id2, id3, id4, id5); + + return ep93xx_soc_id; +} + +static const char __init *ep93xx_get_soc_rev(void) +{ + int rev = ep93xx_chip_revision(); + + switch (rev) { + case EP93XX_CHIP_REV_D0: + return "D0"; + case EP93XX_CHIP_REV_D1: + return "D1"; + case EP93XX_CHIP_REV_E0: + return "E0"; + case EP93XX_CHIP_REV_E1: + return "E1"; + case EP93XX_CHIP_REV_E2: + return "E2"; + default: + return "unknown"; + } +} + +static const char __init *ep93xx_get_machine_name(void) +{ + return kasprintf(GFP_KERNEL,"%s", machine_desc->name); +} + +static struct device __init *ep93xx_init_soc(void) +{ + struct soc_device_attribute *soc_dev_attr; + struct soc_device *soc_dev; + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + return NULL; + + soc_dev_attr->machine = ep93xx_get_machine_name(); + soc_dev_attr->family = "Cirrus Logic EP93xx"; + soc_dev_attr->revision = ep93xx_get_soc_rev(); + soc_dev_attr->soc_id = ep93xx_get_soc_id(); + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + kfree(soc_dev_attr->machine); + kfree(soc_dev_attr); + return NULL; + } + + return soc_device_to_device(soc_dev); +} + +struct device __init *ep93xx_init_devices(void) +{ + struct device *parent; + + /* Disallow access to MaverickCrunch initially */ + ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_CPENA); + + /* Default all ports to GPIO */ + ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_KEYS | + EP93XX_SYSCON_DEVCFG_GONK | + EP93XX_SYSCON_DEVCFG_EONIDE | + EP93XX_SYSCON_DEVCFG_GONIDE | + EP93XX_SYSCON_DEVCFG_HONIDE); + + parent = ep93xx_init_soc(); + + /* Get the GPIO working early, other devices need it */ + platform_device_register(&ep93xx_gpio_device); amba_device_register(&uart1_device, &iomem_resource); amba_device_register(&uart2_device, &iomem_resource); @@ -568,4 +1051,26 @@ void __init ep93xx_init_devices(void) platform_device_register(&ep93xx_rtc_device); platform_device_register(&ep93xx_ohci_device); + platform_device_register(&ep93xx_wdt_device); + + gpio_led_register_device(-1, &ep93xx_led_data); + + return parent; +} + +void ep93xx_restart(enum reboot_mode mode, const char *cmd) +{ + /* + * Set then clear the SWRST bit to initiate a software reset + */ + ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_SWRST); + ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_SWRST); + + while (1) + ; +} + +void __init ep93xx_init_late(void) +{ + crunch_init(); } |
