diff options
Diffstat (limited to 'arch/arm/mach-ns9xxx/ns9360_devices.c')
-rw-r--r-- | arch/arm/mach-ns9xxx/ns9360_devices.c | 813 |
1 files changed, 813 insertions, 0 deletions
diff --git a/arch/arm/mach-ns9xxx/ns9360_devices.c b/arch/arm/mach-ns9xxx/ns9360_devices.c new file mode 100644 index 000000000000..63d2d1205c0c --- /dev/null +++ b/arch/arm/mach-ns9xxx/ns9360_devices.c @@ -0,0 +1,813 @@ +/* + * arch/arm/mach-ns9xxx/ns9360_devices.c + * + * Copyright (C) 2008 by Digi International Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/gpio.h> +#include <linux/ns9xxx-eth.h> +#include <linux/platform_device.h> + +#include <mach/regs-lcd-ns9360.h> +#include <mach/regs-sys-ns9360.h> +#include <mach/gpio.h> +#include <mach/ns9360fb.h> +#include <mach/display/displays.h> + +#include "clock.h" +#include "ns9360_devices.h" + + +/* USB host */ +#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) +static int usbh_endisable(struct clk *clk, int enable) +{ + if (enable) { + u32 mrst = __raw_readl(NS9360_BBU_MSR); + mrst |= 1 << 11; + __raw_writel(mrst, NS9360_BBU_MSR); + + __raw_writel(0 << 2, NS9360_BBUS_USB); + + mrst = __raw_readl(NS9360_BBU_MSR); + mrst &= ~(1 << 11); + __raw_writel(mrst, NS9360_BBU_MSR); + } + + return 0; +} + +static struct clk usbh_clk = { + .name = "ns9360-ohci", + .id = -1, + .owner = THIS_MODULE, + .endisable = usbh_endisable, +}; + +static u64 ohci_dmamask = DMA_BIT_MASK(32); +static struct resource usbh_resources[] = { + { + .start = 0x90801000, + .end = 0x90801fff, + .flags = IORESOURCE_MEM, + }, { + .start = 0x90800000, + .end = 0x90800fff, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_NS9360_USBHOST, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device ns9xxx_device_ns9360_usbh = { + .name = "ns9360-ohci", + .id = -1, + .resource = usbh_resources, + .num_resources = ARRAY_SIZE(usbh_resources), + .dev = { + .dma_mask = &ohci_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +void __init ns9xxx_add_device_ns9360_usbh(void) +{ + if (clk_register(&usbh_clk)) + return; + + platform_device_register(&ns9xxx_device_ns9360_usbh); +} +#else +void __init ns9xxx_add_device_ns9360_usbh(void) {} +#endif + +/* Watchdog timer */ +#if defined(CONFIG_NS9XXX_WATCHDOG) || defined(CONFIG_NS9XXX_WATCHDOG_MODULE) +static struct clk wdt_clk = { + .name = "ns9xxx-wdt", + .id = -1, + .owner = THIS_MODULE, +}; + +static struct resource wdt_resources[] = { + { + .start = 0xa0900174, + .end = 0xa0900177, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device ns9xxx_device_ns9360_wdt = { + .name = "ns9xxx-wdt", + .id = -1, + .resource = wdt_resources, + .num_resources = ARRAY_SIZE(wdt_resources), +}; + +void __init ns9xxx_add_device_ns9360_wdt(void) +{ + wdt_clk.parent = clk_get(NULL, "cpuclock"); + if (IS_ERR(wdt_clk.parent)) + return; + + if (clk_register(&wdt_clk)) + return; + + platform_device_register(&ns9xxx_device_ns9360_wdt); +} +#else +void __init ns9xxx_add_device_ns9360_wdt(void) {} +#endif + +/* RTC */ +#if defined(CONFIG_RTC_DRV_NS9XXX) || defined(CONFIG_RTC_DRV_NS9XXX_MODULE) +static struct clk rtc_clk = { + .name = "rtc-ns9xxx", + .id = -1, + .owner = THIS_MODULE, +}; + +static struct resource rtc_resources[] = { + { + .start = 0x90700000, + .end = 0x907000ff, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_NS9360_RTC, + .flags = IORESOURCE_IRQ, + } +}; + +static struct platform_device ns9xxx_device_ns9360_rtc = { + .name = "rtc-ns9xxx", + .id = 0, + .resource = rtc_resources, + .num_resources = ARRAY_SIZE(rtc_resources), +}; + +void __init ns9xxx_add_device_ns9360_rtc(void) +{ + struct clk *sysclk = clk_get(NULL, "systemclock"); + if (IS_ERR(sysclk)) + return; + + __raw_writel(clk_get_rate(sysclk) / 200, SYS_RTCCC); + clk_put(sysclk); + + if (clk_register(&rtc_clk)) + return; + + platform_device_register(&ns9xxx_device_ns9360_rtc); +} +#else +void __init ns9xxx_add_device_ns9360_rtc(void) {} +#endif + +/* Ethernet */ +#if defined(CONFIG_NS9XXX_ETH) || defined(CONFIG_NS9XXX_ETH_MODULE) +int __init eth_register_gpios(int gpio[], int gpio_nr, int func) +{ + int i; + + for (i = 0; i < gpio_nr; i++) { + if (gpio_request(gpio[i], "ns9xxx-eth")) + goto err; + gpio_configure_ns9360(gpio[i], 0, 0, func); + } + + return 0; +err: + for (; i >= 0; i--) + gpio_free(gpio[i]); + + return -EBUSY; +} + +static struct clk eth_clk = { + .name = "ns9xxx-eth", + .id = -1, + .owner = THIS_MODULE, +}; + +static struct plat_ns9xxx_eth ns9xxx_device_ns9360_eth_data = { + .irqrx = IRQ_NS9XXX_ETHRX, + .irqtx = IRQ_NS9XXX_ETHTX, +}; + +static struct resource eth_resources[] = { + { + .start = 0xa0600000, + .end = 0xa06027ff, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device ns9xxx_device_ns9360_eth = { + .name = "ns9xxx-eth", + .id = -1, + .resource = eth_resources, + .num_resources = ARRAY_SIZE(eth_resources), + .dev = { + .platform_data = &ns9xxx_device_ns9360_eth_data, + }, +}; + +void __init ns9xxx_add_device_ns9360_eth(int gpio[], int gpio_nr, int func, u32 phy_mask) +{ + if (eth_register_gpios(gpio, gpio_nr, func)) + return; + + if (clk_register(ð_clk)) + return; + + ns9xxx_device_ns9360_eth_data.phy_mask = phy_mask; + + platform_device_register(&ns9xxx_device_ns9360_eth); +} +#else +void __init ns9xxx_add_device_ns9360_eth(int gpio[], int gpio_nr, int func, u32 phy_mask) {} +#endif + +/* UARTs */ +#if defined(CONFIG_SERIAL_NS9360) || defined(CONFIG_SERIAL_NS9360_MODULE) +static struct clk uarta_clk = { + .name = "ns9360-serial", + .id = 1, + .owner = THIS_MODULE, +}; + +static struct clk uartb_clk = { + .name = "ns9360-serial", + .id = 0, + .owner = THIS_MODULE, +}; + +static struct clk uartc_clk = { + .name = "ns9360-serial", + .id = 2, + .owner = THIS_MODULE, +}; + +static struct clk uartd_clk = { + .name = "ns9360-serial", + .id = 3, + .owner = THIS_MODULE, +}; + +static struct resource uarta_resources[] = { + { + .start = 0x90200040, + .end = 0x9020007f, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_NS9360_SERARX, + .flags = IORESOURCE_IRQ, + } +}; + +static struct resource uartb_resources[] = { + { + .start = 0x90200000, + .end = 0x9020003f, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_NS9360_SERBRX, + .flags = IORESOURCE_IRQ, + } +}; + +static struct resource uartc_resources[] = { + { + .start = 0x90300000, + .end = 0x9030003f, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_NS9360_SERCRX, + .flags = IORESOURCE_IRQ, + } +}; + +static struct resource uartd_resources[] = { + { + .start = 0x90300040, + .end = 0x9030007f, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_NS9360_BBUS_SERDRX, + .flags = IORESOURCE_IRQ, + } +}; + +static struct platform_device ns9xxx_device_ns9360_uarta = { + .name = "ns9360-serial", + .id = 1, + .resource = uarta_resources, + .num_resources = ARRAY_SIZE(uarta_resources), +}; + +static struct platform_device ns9xxx_device_ns9360_uartb = { + .name = "ns9360-serial", + .id = 0, + .resource = uartb_resources, + .num_resources = ARRAY_SIZE(uartb_resources), +}; + +static struct platform_device ns9xxx_device_ns9360_uartc = { + .name = "ns9360-serial", + .id = 2, + .resource = uartc_resources, + .num_resources = ARRAY_SIZE(uartc_resources), +}; + +static struct platform_device ns9xxx_device_ns9360_uartd = { + .name = "ns9360-serial", + .id = 3, + .resource = uartd_resources, + .num_resources = ARRAY_SIZE(uartd_resources), +}; + +int __init uart_register_gpios(int gpio[], int gpio_nr, int func) +{ + int i; + + for (i = 0; i < gpio_nr; i++) { + if (gpio_request(gpio[i], "ns9360-serial")) + goto err; + gpio_configure_ns9360(gpio[i], 0, 0, func); + } + + return 0; +err: + for (; i >= 0; i--) + gpio_free(gpio[i]); + + return -EBUSY; +} + +void __init ns9xxx_add_device_ns9360_uarta(int gpio[], int gpio_nr, int func) +{ + if (uart_register_gpios(gpio, gpio_nr, func)) + return; + + uarta_clk.parent = clk_get(NULL, "bbusclock"); + if (IS_ERR(uarta_clk.parent)) + return; + + if (clk_register(&uarta_clk)) + return; + + platform_device_register(&ns9xxx_device_ns9360_uarta); +} + +void __init ns9xxx_add_device_ns9360_uartb(int gpio[], int gpio_nr, int func) +{ + if (uart_register_gpios(gpio, gpio_nr, func)) + return; + + uartb_clk.parent = clk_get(NULL, "bbusclock"); + if (IS_ERR(uartb_clk.parent)) + return; + + if (clk_register(&uartb_clk)) + return; + + platform_device_register(&ns9xxx_device_ns9360_uartb); +} + +void __init ns9xxx_add_device_ns9360_uartc(int gpio[], int gpio_nr, int func) +{ + if (uart_register_gpios(gpio, gpio_nr, func)) + return; + + uartc_clk.parent = clk_get(NULL, "bbusclock"); + if (IS_ERR(uartc_clk.parent)) + return; + + if (clk_register(&uartc_clk)) + return; + + platform_device_register(&ns9xxx_device_ns9360_uartc); +} + +void __init ns9xxx_add_device_ns9360_uartd(int gpio[], int gpio_nr, int func) +{ + if (uart_register_gpios(gpio, gpio_nr, func)) + return; + + uartd_clk.parent = clk_get(NULL, "bbusclock"); + if (IS_ERR(uartd_clk.parent)) + return; + + if (clk_register(&uartd_clk)) + return; + + platform_device_register(&ns9xxx_device_ns9360_uartd); +} +#else +void __init ns9xxx_add_device_ns9360_uarta(int gpio[], int gpio_nr, int func) {} +void __init ns9xxx_add_device_ns9360_uartb(int gpio[], int gpio_nr, int func) {} +void __init ns9xxx_add_device_ns9360_uartc(int gpio[], int gpio_nr, int func) {} +void __init ns9xxx_add_device_ns9360_uartd(int gpio[], int gpio_nr, int func) {} +#endif + +/* NAND flash */ +#if defined(CONFIG_MTD_NAND_CCX9X) || defined(CONFIG_MTD_NAND_CCX9X_MODULE) +static struct resource nand_resources[] = { + { + .start = 0x50000000, + .end = 0x5fffffff, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device ns9xxx_device_ns9360_nand = { + .name = "ccx9x_nand", + .id = -1, + .resource = nand_resources, + .num_resources = ARRAY_SIZE(nand_resources), +}; + +void __init ns9xxx_add_device_ns9360_nand(struct ccx9x_nand_info *nand_data) +{ + ns9xxx_device_ns9360_nand.dev.platform_data = nand_data; + platform_device_register(&ns9xxx_device_ns9360_nand); +} +#else +void __init ns9xxx_add_device_ns9360_nand(struct ccx9x_nand_info *nand_data) {} +#endif + +/* I2C controller */ +#if defined(CONFIG_I2C_NS9XXX) || defined(CONFIG_I2C_NS9XXX_MODULE) +static struct clk i2c_clk = { + .name = "i2c-ns9xxx", + .id = -1, + .owner = THIS_MODULE, +}; + +static struct resource i2c_resources[] = { + { + .start = 0x90500000, + .end = 0x9050000f, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_NS9360_I2C, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device ns9xxx_device_ns9360_i2c = { + .name = "i2c-ns9xxx", + .id = -1, + .resource = i2c_resources, + .num_resources = ARRAY_SIZE(i2c_resources), +}; + +void __init ns9xxx_add_device_ns9360_i2c(struct plat_ns9xxx_i2c *i2c_data) +{ + i2c_clk.parent = clk_get(NULL, "systemclock"); + if (IS_ERR(i2c_clk.parent)) + return; + + if (clk_register(&i2c_clk)) + return; + + ns9xxx_device_ns9360_i2c.dev.platform_data = i2c_data; + platform_device_register(&ns9xxx_device_ns9360_i2c); +} +#else +void __init ns9xxx_add_device_ns9360_i2c(struct plat_ns9xxx_i2c *i2c_data) {} +#endif + +/* Framebuffer controller */ +#if (defined(CONFIG_FB_NS9360) || defined(CONFIG_FB_NS9360_MODULE)) && !defined(NS9XXX_NODISPLAY) +int __init fb_register_gpios(int gpio[], int gpio_nr, int func[], int power) +{ + int i; + + for (i = 0; i < gpio_nr; i++) { + if (gpio_request(gpio[i], "ns9360fb")) + goto err; + gpio_configure_ns9360(gpio[i], 0, 0, func[i]); + } + + if (gpio_request(power, "ns9360fb")) { + i--; + goto err; + } + gpio_direction_output(power, 0); + + return 0; +err: + for (; i >= 0; i--) + gpio_free(gpio[i]); + + return -EBUSY; +} + +static int fb_endisable(struct clk *clk, int enable) +{ + /* Currently, nothing to do */ + return 0; +} + +static struct clk fb_clk = { + .name = "ns9360fb", + .id = -1, + .owner = THIS_MODULE, + .endisable = fb_endisable, + +}; +static struct ns9360fb_pdata ns9xxx_device_ns9360_fb_data = { + .displays = display_list, + .num_displays = ARRAY_SIZE(display_list), +}; + +static struct resource fb_resources[] = { + { + .start = 0xa0800000, + .end = 0xa080002f, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device ns9xxx_device_ns9360_fb = { + .name = "ns9360fb", + .id = -1, + .resource = fb_resources, + .num_resources = ARRAY_SIZE(fb_resources), + .dev = { + .platform_data = &ns9xxx_device_ns9360_fb_data, + }, +}; + +void __init ns9xxx_add_device_ns9360_fb(int gpio[], int gpio_nr, + int func[], int power) +{ + fb_clk.parent = clk_get(NULL, "ahbclock"); + if (IS_ERR(fb_clk.parent)) + return; + + if (clk_register(&fb_clk)) + return; + + if (fb_register_gpios(gpio, gpio_nr, func, power)) + return; + + platform_device_register(&ns9xxx_device_ns9360_fb); +} +#else +void __init ns9xxx_add_device_ns9360_fb(int gpio[], int gpio_nr, + int func[], int power) {} +#endif + +#if defined(CONFIG_SPI_NS9360) || defined(CONFIG_SPI_NS9360_MODULE) +int __init spi_register_gpios(struct spi_ns9xxx_data *data) +{ + int i; + + for (i = 0; i < data->nr_gpios; i++) { + if (gpio_request(data->gpios[i], "spi_ns9360")) + goto err; + gpio_configure_ns9360( data->gpios[i], + 0, + 0, + data->gpio_funcs[i] ); + } + + return 0; +err: + for (; i >= 0; i--) + gpio_free(data->gpios[i]); + + return -EBUSY; +} + +static struct clk spi_porta_clk = { + .name = "spi_ns9360", + .id = 1, + .owner = THIS_MODULE, +}; + +static struct clk spi_portb_clk = { + .name = "spi_ns9360", + .id = 0, + .owner = THIS_MODULE, +}; + +static struct clk spi_portc_clk = { + .name = "spi_ns9360", + .id = 2, + .owner = THIS_MODULE, +}; + +static struct clk spi_portd_clk = { + .name = "spi_ns9360", + .id = 3, + .owner = THIS_MODULE, +}; + +static struct resource spi_porta_resources[] = { + { + .start = 0x90200040, + .end = 0x9020007f, + .flags = IORESOURCE_MEM, + }, { + .start = 0x90000040, + .end = 0x9000007f, + .flags = IORESOURCE_MEM, + }, { + .start = 60, + .flags = IORESOURCE_IRQ, + }, { + .start = 61, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource spi_portb_resources[] = { + { + .start = 0x90200000, + .end = 0x9020003f, + .flags = IORESOURCE_MEM, + }, { + .start = 0x90000000, + .end = 0x9000003f, + .flags = IORESOURCE_MEM, + }, { + .start = 58, + .flags = IORESOURCE_IRQ, + }, { + .start = 59, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource spi_portc_resources[] = { + { + .start = 0x90300000, + .end = 0x9020003f, + .flags = IORESOURCE_MEM, + }, { + .start = 0x90000080, + .end = 0x900000bf, + .flags = IORESOURCE_MEM, + }, { + .start = 62, + .flags = IORESOURCE_IRQ, + }, { + .start = 63, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource spi_portd_resources[] = { + { + .start = 0x90300040, + .end = 0x9030007f, + .flags = IORESOURCE_MEM, + }, { + .start = 0x900000c0, + .end = 0x900000ff, + .flags = IORESOURCE_MEM, + }, { + .start = 64, + .flags = IORESOURCE_IRQ, + }, { + .start = 65, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 spi_dmamask = DMA_BIT_MASK(32); + +static struct platform_device ns9xxx_device_ns9360_spi_porta = { + .name = "spi_ns9360", + .id = 1, + .resource = spi_porta_resources, + .num_resources = ARRAY_SIZE(spi_porta_resources), + .dev = { + .dma_mask = &spi_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +static struct platform_device ns9xxx_device_ns9360_spi_portb = { + .name = "spi_ns9360", + .id = 0, + .resource = spi_portb_resources, + .num_resources = ARRAY_SIZE(spi_portb_resources), + .dev = { + .dma_mask = &spi_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +static struct platform_device ns9xxx_device_ns9360_spi_portc = { + .name = "spi_ns9360", + .id = 2, + .resource = spi_portc_resources, + .num_resources = ARRAY_SIZE(spi_portc_resources), + .dev = { + .dma_mask = &spi_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +static struct platform_device ns9xxx_device_ns9360_spi_portd = { + .name = "spi_ns9360", + .id = 3, + .resource = spi_portd_resources, + .num_resources = ARRAY_SIZE(spi_portd_resources), + .dev = { + .dma_mask = &spi_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +void __init ns9xxx_add_device_ns9360_spi_porta(struct spi_ns9xxx_data *data) +{ + if (spi_register_gpios(data)) + return; + + spi_porta_clk.parent = clk_get(NULL, "bbusclock"); + if (IS_ERR(spi_porta_clk.parent)) + return; + + if (clk_register(&spi_porta_clk)) + return; + + /* Set platform data */ + ns9xxx_device_ns9360_spi_porta.dev.platform_data = data; + + platform_device_register(&ns9xxx_device_ns9360_spi_porta); +} + +void __init ns9xxx_add_device_ns9360_spi_portb( struct spi_ns9xxx_data *data ) +{ + if (spi_register_gpios(data)) + return; + + spi_portb_clk.parent = clk_get(NULL, "bbusclock"); + if (IS_ERR(spi_portb_clk.parent)) + return; + + if (clk_register(&spi_portb_clk)) + return; + + /* Set platform data */ + ns9xxx_device_ns9360_spi_portb.dev.platform_data = data; + + platform_device_register(&ns9xxx_device_ns9360_spi_portb); +} + + +void __init ns9xxx_add_device_ns9360_spi_portc(struct spi_ns9xxx_data *data) +{ + if (spi_register_gpios(data)) + return; + + spi_portc_clk.parent = clk_get(NULL, "bbusclock"); + if (IS_ERR(spi_portc_clk.parent)) + return; + + if (clk_register(&spi_portc_clk)) + return; + + /* Set platform data */ + ns9xxx_device_ns9360_spi_portc.dev.platform_data = data; + + platform_device_register(&ns9xxx_device_ns9360_spi_portc); +} + +void __init ns9xxx_add_device_ns9360_spi_portd(struct spi_ns9xxx_data *data) +{ + if (spi_register_gpios(data)) + return; + + spi_portd_clk.parent = clk_get(NULL, "bbusclock"); + if (IS_ERR(spi_portd_clk.parent)) + return; + + if (clk_register(&spi_portd_clk)) + return; + + /* Set platform data */ + ns9xxx_device_ns9360_spi_portd.dev.platform_data = data; + + platform_device_register(&ns9xxx_device_ns9360_spi_portd); +} +#else +void __init ns9xxx_add_device_ns9360_spi_porta(struct spi_ns9xxx_data *data) {} +void __init ns9xxx_add_device_ns9360_spi_portb(struct spi_ns9xxx_data *data) {} +void __init ns9xxx_add_device_ns9360_spi_portc(struct spi_ns9xxx_data *data) {} +void __init ns9xxx_add_device_ns9360_spi_portd(struct spi_ns9xxx_data *data) {} +#endif |