diff options
Diffstat (limited to 'arch/arm/mach-ns9xxx')
80 files changed, 9812 insertions, 472 deletions
diff --git a/arch/arm/mach-ns9xxx/Kconfig b/arch/arm/mach-ns9xxx/Kconfig index dd0cd5ac4b8b..7edebdcf1c59 100644 --- a/arch/arm/mach-ns9xxx/Kconfig +++ b/arch/arm/mach-ns9xxx/Kconfig @@ -2,29 +2,149 @@ if ARCH_NS9XXX menu "NS9xxx Implementations" -config NS9XXX_HAVE_SERIAL8250 +config DIGI_UNSUPPORTED + def_bool n + help + This symbol is used to disable some options in the kernel + configuration that are not supported by Digi Embedded Linux. + +config PROCESSOR_NS921X + bool + +config RESET_DISABLED_MODULES + bool "reset disabled modules" + depends on BROKEN && PROCESSOR_NS921X + help + If you say Y here, cpu components that are not used are not only + disabled in the SYS_CLOCK register but also reset using the SYS_RESET + + Currently this breaks the serial console. + +config PROCESSOR_NS9210 + bool + select PROCESSOR_NS921X + +config PROCESSOR_NS9215 bool + select PROCESSOR_NS921X config PROCESSOR_NS9360 bool + select USB_ARCH_HAS_OHCI + +config MODULE_CC9C + bool + select PROCESSOR_NS9360 + +config MODULE_CC7UCAMRY + bool + select PROCESSOR_NS9210 + +config MODULE_CC9P9215 + bool + select PROCESSOR_NS9215 + +config MODULE_CCW9P9215 + bool + select PROCESSOR_NS9215 config MODULE_CC9P9360 bool select PROCESSOR_NS9360 +config MODULE_CME9210 + bool + select PROCESSOR_NS9210 + +config MODULE_CCW9C + bool + select PROCESSOR_NS9360 + +config MODULE_INC20OTTER + bool + select PROCESSOR_NS9210 + config BOARD_A9M9750DEV - select NS9XXX_HAVE_SERIAL8250 + bool + +config BOARD_JSCC9P9215 + bool + +config BOARD_JSCCW9P9215 bool config BOARD_JSCC9P9360 bool +config BOARD_JSCME9210 + bool + +config BOARD_UNCBAS + bool + +choice + prompt "NS9xxx Implementations" + +config MACH_CC7UCAMRY + bool "ConnectCore 7U Camry" + depends on DIGI_UNSUPPORTED + select MODULE_CC7UCAMRY + select BOARD_UNCBAS + help + Say Y here if you are using the CC7U Camry module. + + This is a modified ConnectCore 7U with an NS9210 processor + instead of an NS7520. + +config MACH_CC9C + bool "ConnectCore 9C" + select MODULE_CC9C + help + Say Y here if you are using the ConnectCore 9C. + +config MACH_CCW9C + bool "ConnectCore Wi-9C" + select MODULE_CCW9C + help + Say Y here if you are using the ConnectCore Wi-9C. + +config MACH_CC9P9215 + bool "ConnectCore 9P 9215" + select MODULE_CC9P9215 + help + Say Y here if you are using the ConnectCore 9P 9215 module on an + currently unsupported board. + +config MACH_CC9P9215JS + bool "ConnectCore 9P 9215 on a JSCC9P9215 Devboard" + select MODULE_CC9P9215 + select BOARD_JSCC9P9215 + help + Say Y here if you are using the ConnectCore 9P 9215 module + on a JSCC9P9215 Development Board. + +config MACH_CCW9P9215 + bool "ConnectCore Wi-9P 9215" + select MODULE_CCW9P9215 + help + Say Y here if you are using the ConnectCore Wi-9P 9215 module on an + currently unsupported board. + +config MACH_CCW9P9215JS + bool "ConnectCore Wi-9P 9215 on a JSCCW9P9215 Devboard" + select MODULE_CCW9P9215 + select BOARD_JSCCW9P9215 + help + Say Y here if you are using the ConnectCore Wi-9P 9215 module + on a JSCCW9P9215 Development Board. + config MACH_CC9P9360DEV bool "ConnectCore 9P 9360 on an A9M9750 Devboard" + depends on DIGI_UNSUPPORTED select MODULE_CC9P9360 select BOARD_A9M9750DEV help - Say Y here if you are using the Digi ConnectCore 9P 9360 + Say Y here if you are using the ConnectCore 9P 9360 on an A9M9750 Development Board. config MACH_CC9P9360JS @@ -32,8 +152,482 @@ config MACH_CC9P9360JS select MODULE_CC9P9360 select BOARD_JSCC9P9360 help - Say Y here if you are using the Digi ConnectCore 9P 9360 - on an JSCC9P9360 Development Board. + Say Y here if you are using the ConnectCore 9P 9360 + on a JSCC9P9360 Development Board. + +config MACH_CME9210 + bool "Digi Connect ME 9210" + select MODULE_CME9210 + +config MACH_CME9210JS + bool "Digi Connect ME 9210 on Devboard" + select MODULE_CME9210 + select BOARD_JSCME9210 + +config MACH_INC20OTTER + bool "Inc20-Otter" + depends on DIGI_UNSUPPORTED + select MODULE_INC20OTTER + +config MACH_OTTER + bool "Otter" + depends on DIGI_UNSUPPORTED + select PROCESSOR_NS9210 + +endchoice + +config NS9XXX_HAVE_GPIO_LIB + bool "Use GPIO_LIB" if DIGI_UNSUPPORTED + default y + select ARCH_REQUIRE_GPIOLIB + +if (MACH_CC9C || MACH_CCW9C) + +comment "ConnectCore 9C/Wi-9C configuration" + +config CCX9C_SERIAL_PORTA + bool "Serial port A" + default y + depends on SERIAL_NS9360 && !CCX9C_SPI_PORTA + +choice + prompt "port configuration" + depends on CCX9C_SERIAL_PORTA + default CCX9C_SERIAL_PORTA_FULL + +config CCX9C_SERIAL_PORTA_RXTX + bool "RX/TX only" + +config CCX9C_SERIAL_PORTA_CTSRTSRXTX + bool "CTS/RTS/RX/TX" + +config CCX9C_SERIAL_PORTA_FULL + bool "Full port" + +endchoice + +config CCX9C_SPI_PORTA + bool "SPI port A" + default n + depends on SPI_NS9360 + +config CCX9C_SERIAL_PORTB + bool "Serial port B" + default y + depends on SERIAL_NS9360 && !CCX9C_SPI_PORTB + +choice + prompt "port configuration" + depends on CCX9C_SERIAL_PORTB + default CCX9C_SERIAL_PORTB_FULL + +config CCX9C_SERIAL_PORTB_RXTX + bool "RX/TX only" + +config CCX9C_SERIAL_PORTB_CTSRTSRXTX + bool "CTS/RTS/RX/TX" + +config CCX9C_SERIAL_PORTB_FULL + bool "Full port" + +endchoice + +config CCX9C_SPI_PORTB + bool "SPI port B" + default y + depends on SPI_NS9360 + +config CCX9C_SERIAL_PORTC + bool "Serial port C" + default y + depends on SERIAL_NS9360 && !CCX9C_SPI_PORTC && !CCX9C_FB + +choice + prompt "port configuration" + depends on CCX9C_SERIAL_PORTC + default CCX9C_SERIAL_PORTC_FULL + +config CCX9C_SERIAL_PORTC_RXTX + bool "RX/TX only" + +config CCX9C_SERIAL_PORTC_CTSRTSRXTX + bool "CTS/RTS/RX/TX" + +config CCX9C_SERIAL_PORTC_FULL + bool "Full port" + +endchoice + +config CCX9C_SPI_PORTC + bool "SPI port C" + default n + depends on SPI_NS9360 && !CCX9C_FB + +config CCX9C_SERIAL_PORTD + bool "Serial port D" + default y + depends on SERIAL_NS9360 && !CCX9C_SPI_PORTD && !CCX9C_FB + +choice + prompt "port configuration" + depends on CCX9C_SERIAL_PORTD + default CCX9C_SERIAL_PORTD_FULL + +config CCX9C_SERIAL_PORTD_RXTX + bool "RX/TX only" + +config CCX9C_SERIAL_PORTD_CTSRTSRXTX + bool "CTS/RTS/RX/TX" + +config CCX9C_SERIAL_PORTD_FULL + bool "Full port" + +endchoice + +config CCX9C_SPI_PORTD + bool "SPI port D" + default n + depends on SPI_NS9360 && !CCX9C_FB + +config CCX9C_FB + bool "Framebuffer" + default y + depends on FB_NS9360 + +config CCX9C_TOUCH + bool "Touchscreen" + default y + depends on TOUCHSCREEN_ADS7846 && CCX9C_FB && CCX9C_SPI_PORTB + +endif ## if (MACH_CC9C || MACH_CCW9C) + + +if (MACH_CC9P9215JS || MACH_CCW9P9215JS) + +comment "ConnectCore 9P/Wi-9P 9215 configuration" + +config CC9P9215JS_SERIAL_PORTA + bool "Serial port A" + default y + depends on SERIAL_NS921X && !CC9P9215JS_SPI + +choice + prompt "port configuration" + depends on CC9P9215JS_SERIAL_PORTA + default CC9P9215JS_SERIAL_PORTA_FULL + +config CC9P9215JS_SERIAL_PORTA_RXTX + bool "RX/TX only" + +config CC9P9215JS_SERIAL_PORTA_RXTX485 + bool "RX/TX/RTS (RTS for RS-485 transceiver control)" + help + This mode enables the RS-485 transceiver control functionality + of the RTS line in the serial port. + +config CC9P9215JS_SERIAL_PORTA_CTSRTSRXTX + bool "CTS/RTS/RX/TX" + +config CC9P9215JS_SERIAL_PORTA_FULL + bool "Full port" + +endchoice + +config CC9P9215JS_SERIAL_PORTB + bool "Serial port B" + default y + depends on SERIAL_NS921X + +choice + prompt "port configuration" + depends on CC9P9215JS_SERIAL_PORTB + default CC9P9215JS_SERIAL_PORTB_FULL + +config CC9P9215JS_SERIAL_PORTB_RXTX + bool "RX/TX only" + +config CC9P9215JS_SERIAL_PORTB_RXTX485 + bool "RX/TX/RTS (RTS for RS-485 transceiver control)" + help + This mode enables the RS-485 transceiver control functionality + of the RTS line in the serial port. + +config CC9P9215JS_SERIAL_PORTB_CTSRTSRXTX + bool "CTS/RTS/RX/TX" + +config CC9P9215JS_SERIAL_PORTB_FULL + bool "Full port" + +endchoice + +config CC9P9215JS_SERIAL_PORTC + bool "Serial port C" + default y + depends on SERIAL_NS921X + +choice + prompt "port configuration" + depends on CC9P9215JS_SERIAL_PORTC + default CC9P9215JS_SERIAL_PORTC_FULL + +config CC9P9215JS_SERIAL_PORTC_RXTX + bool "RX/TX only" + +config CC9P9215JS_SERIAL_PORTC_RXTX485 + bool "RX/TX/RTS (RTS for RS-485 transceiver control)" + help + This mode enables the RS-485 transceiver control functionality + of the RTS line in the serial port. + +config CC9P9215JS_SERIAL_PORTC_CTSRTSRXTX + bool "CTS/RTS/RX/TX" + +config CC9P9215JS_SERIAL_PORTC_FULL + bool "Full port" + +endchoice + +config CC9P9215JS_SERIAL_PORTD + bool "Serial port D" + default y + depends on SERIAL_NS921X + +choice + prompt "port configuration" + depends on CC9P9215JS_SERIAL_PORTD + default CC9P9215JS_SERIAL_PORTD_FULL + +config CC9P9215JS_SERIAL_PORTD_RXTX + bool "RX/TX only" + +config CC9P9215JS_SERIAL_PORTD_RXTX485 + bool "RX/TX/RTS (RTS for RS-485 transceiver control)" + help + This mode enables the RS-485 transceiver control functionality + of the RTS line in the serial port. + +config CC9P9215JS_SERIAL_PORTD_CTSRTSRXTX + bool "CTS/RTS/RX/TX" + +config CC9P9215JS_SERIAL_PORTD_FULL + bool "Full port" + +endchoice + +config CC9P9215JS_SPI + bool "SPI port" + default y + depends on SPI_NS921X + +config CC9P9215JS_EDT_DISPLAY_QVGA + bool "Support for the EDT QVGA TFT Display" + default n + select FB_HX8347 + +config CC9P9215JS_TOUCH + bool "Touchscreen" + default y + depends on TOUCHSCREEN_ADS7846 && CC9P9215JS_EDT_DISPLAY_QVGA && CC9P9215JS_SPI + +endif ## if (MACH_CC9P9215JS || MACH_CCW9P9215JS) + + +if MACH_CC9P9360JS + +comment "ConnectCore 9P 9360 configuration" + +config CC9P9360JS_SERIAL_PORTA + bool "Serial port A" + default y + depends on SERIAL_NS9360 && !CC9P9360JS_SPI_PORTA + +choice + prompt "port configuration" + depends on CC9P9360JS_SERIAL_PORTA + default CC9P9360JS_SERIAL_PORTA_FULL + +config CC9P9360JS_SERIAL_PORTA_RXTX + bool "RX/TX only" + +config CC9P9360JS_SERIAL_PORTA_CTSRTSRXTX + bool "CTS/RTS/RX/TX" + +config CC9P9360JS_SERIAL_PORTA_FULL + bool "Full port" + +endchoice + +config CC9P9360JS_SPI_PORTA + bool "SPI port A" + default n + depends on SPI_NS9360 + +config CC9P9360JS_SERIAL_PORTB + bool "Serial port B" + default y + depends on SERIAL_NS9360 && !CC9P9360JS_SPI_PORTB + +choice + prompt "port configuration" + depends on CC9P9360JS_SERIAL_PORTB + default CC9P9360JS_SERIAL_PORTB_FULL + +config CC9P9360JS_SERIAL_PORTB_RXTX + bool "RX/TX only" + +config CC9P9360JS_SERIAL_PORTB_CTSRTSRXTX + bool "CTS/RTS/RX/TX" + +config CC9P9360JS_SERIAL_PORTB_FULL + bool "Full port" + +endchoice + +config CC9P9360JS_SPI_PORTB + bool "SPI port B" + default y + depends on SPI_NS9360 + +config CC9P9360JS_SERIAL_PORTC + bool "Serial port C" + default y + depends on SERIAL_NS9360 && !CC9P9360JS_SPI_PORTC && !CC9P9360JS_FB + +choice + prompt "port configuration" + depends on CC9P9360JS_SERIAL_PORTC + default CC9P9360JS_SERIAL_PORTC_FULL + +config CC9P9360JS_SERIAL_PORTC_RXTX + bool "RX/TX only" + +config CC9P9360JS_SERIAL_PORTC_CTSRTSRXTX + bool "CTS/RTS/RX/TX" + +config CC9P9360JS_SERIAL_PORTC_FULL + bool "Full port" + +endchoice + +config CC9P9360JS_SPI_PORTC + bool "SPI port C" + default n + depends on SPI_NS9360 && !CC9P9360JS_FB + +config CC9P9360JS_SERIAL_PORTD + bool "Serial port D" + default y + depends on SERIAL_NS9360 && !CC9P9360JS_SPI_PORTD && !CC9P9360JS_FB + +choice + prompt "port configuration" + depends on CC9P9360JS_SERIAL_PORTD + default CC9P9360JS_SERIAL_PORTD_FULL + +config CC9P9360JS_SERIAL_PORTD_RXTX + bool "RX/TX only" + +config CC9P9360JS_SERIAL_PORTD_CTSRTSRXTX + bool "CTS/RTS/RX/TX" + +config CC9P9360JS_SERIAL_PORTD_FULL + bool "Full port" + +endchoice + +config CC9P9360JS_SPI_PORTD + bool "SPI port D" + default n + depends on SPI_NS9360 && !CC9P9360JS_FB + +config CC9P9360JS_FB + bool "Framebuffer" + default y + depends on FB_NS9360 + +config CC9P9360JS_TOUCH + bool "Touchscreen" + default y + depends on TOUCHSCREEN_ADS7846 && CC9P9360JS_FB && CC9P9360JS_SPI_PORTB + +# Commented out as cc9p9360 does not assemble 0 ohm R2 +# resistor which routes the RTC alarm to the CPU +#config EXTERNAL_RTC_ALARM +# bool "External RTC Alarm interrupt" +# default n +# depends on !CC9P9360JS_SERIAL_PORTA_FULL +# help +# This enables the interrupt coming from the external +# I2C DS1337 Real Time Clock. +#comment "--- External RTC Alarm interrupt (disable Serial port A Full)" +# depends on CC9P9360JS_SERIAL_PORTA_FULL + +endif ## if MACH_CC9P9360JS + + +if MACH_CME9210JS + +comment "Digi Connect ME 9210 configuration" + +config CME9210JS_SERIAL_PORTA + bool "Serial port A" + default y + depends on SERIAL_NS921X + +choice + prompt "port configuration" + depends on CME9210JS_SERIAL_PORTA + default CME9210JS_SERIAL_PORTA_RXTX + +config CME9210JS_SERIAL_PORTA_RXTX + bool "RX/TX only" + +config CME9210JS_SERIAL_PORTA_RXTX485 + bool "RX/TX/RTS (RTS for RS-485 transceiver control)" + help + This mode enables the RS-485 transceiver control functionality + of the RTS line in the serial port. + +config CME9210JS_SERIAL_PORTA_CTSRTSRXTX + bool "CTS/RTS/RX/TX" + +config CME9210JS_SERIAL_PORTA_FULL + bool "Full port" + +endchoice + +config CME9210JS_SERIAL_PORTC + bool "Serial port C (only modules with JTAG-header)" + depends on SERIAL_NS921X && !I2C_NS9XXX + help + Enable serial port C on Connect ME9210 module. You can only + use this port if your module has the JTAG-header! + This port shares GPIOs with I2C bus, so I2C must be disabled. + +choice + prompt "port configuration" + depends on CME9210JS_SERIAL_PORTC + default CME9210JS_SERIAL_PORTC_RXTX + +config CME9210JS_SERIAL_PORTC_RXTX + bool "RX/TX only" + +endchoice + +config CME9210JS_SPI + bool "SPI port" + depends on !CME9210JS_SERIAL_PORTA + +config GPIO_ETH_ACTIVITY_LED + bool "Ethernet activity LED" + depends on NS9XXX_ETH + default y + help + Enables the use of GPIO14 as Ethernet RX/TX activity LED + +endif ## if MACH_CME9210JS + +source "arch/arm/mach-ns9xxx/include/mach/display/Kconfig" endmenu diff --git a/arch/arm/mach-ns9xxx/Makefile b/arch/arm/mach-ns9xxx/Makefile index 41efaf9ad50b..63aae2d39ef3 100644 --- a/arch/arm/mach-ns9xxx/Makefile +++ b/arch/arm/mach-ns9xxx/Makefile @@ -1,12 +1,45 @@ -obj-y := clock.o generic.o gpio.o irq.o +obj-y := clock.o gpio.o irq.o +ifeq ($(CONFIG_GPIOLIB),y) +gpio-$(CONFIG_PROCESSOR_NS921X) += gpiolib-ns921x.o +gpio-$(CONFIG_PROCESSOR_NS9360) += gpiolib-ns9360.o +endif + +obj-$(CONFIG_MACH_CC7UCAMRY) += mach-cc7ucamry.o +obj-$(CONFIG_MACH_CC9C) += mach-cc9c.o +obj-$(CONFIG_MACH_CC9P9215) += mach-cc9p9215.o +obj-$(CONFIG_MACH_CC9P9215JS) += mach-cc9p9215js.o obj-$(CONFIG_MACH_CC9P9360DEV) += mach-cc9p9360dev.o obj-$(CONFIG_MACH_CC9P9360JS) += mach-cc9p9360js.o +obj-$(CONFIG_MACH_CME9210) += mach-cme9210.o +obj-$(CONFIG_MACH_CME9210JS) += mach-cme9210js.o +obj-$(CONFIG_MACH_CCW9P9215) += mach-ccw9p9215.o +obj-$(CONFIG_MACH_CCW9P9215JS) += mach-ccw9p9215js.o +obj-$(CONFIG_MACH_CCW9C) += mach-ccw9c.o +obj-$(CONFIG_MACH_INC20OTTER) += mach-inc20otter.o +obj-$(CONFIG_MACH_OTTER) += mach-otter.o + +obj-$(CONFIG_PROCESSOR_NS921X) += gpio-ns921x.o irq-ns921x.o processor-ns921x.o time-ns921x.o ns921x_devices.o +obj-$(CONFIG_PROCESSOR_NS9215) += ns9215_devices.o +obj-$(CONFIG_PROCESSOR_NS9360) += gpio-ns9360.o processor-ns9360.o time-ns9360.o ns9360_devices.o + +obj-$(CONFIG_MODULE_CC9P9215) += cc9p9215_devices.o +ifeq ($(CONFIG_MODULE_CCW9P9215),y) +CFLAGS_ccw9p9215_devices.o += -I$(srctree)/drivers/net/wireless/digiPiper/ +CFLAGS_mach-ccw9p9215js.o += -I$(srctree)/drivers/net/wireless/digiPiper/ +endif +obj-$(CONFIG_MODULE_CCW9P9215) += cc9p9215_devices.o ccw9p9215_devices.o +obj-$(CONFIG_MODULE_CC9P9360) += cc9p9360_devices.o +obj-$(CONFIG_MODULE_CC9C) += ccx9c_devices.o +obj-$(CONFIG_MODULE_CCW9C) += ccx9c_devices.o +obj-$(CONFIG_MODULE_CME9210) += cme9210_devices.o -obj-$(CONFIG_PROCESSOR_NS9360) += gpio-ns9360.o processor-ns9360.o time-ns9360.o +obj-$(CONFIG_LEDS_CPU) += leds.o -obj-$(CONFIG_BOARD_A9M9750DEV) += board-a9m9750dev.o -obj-$(CONFIG_BOARD_JSCC9P9360) += board-jscc9p9360.o +# Power Management +obj-$(CONFIG_PM) += pm.o +pm-$(CONFIG_PROCESSOR_NS921X) += pm-ns921x.o +ifeq ($(CONFIG_PM_VERBOSE),y) +CFLAGS_pm-ns921x.o += -DDEBUG +endif -# platform devices -obj-$(CONFIG_NS9XXX_HAVE_SERIAL8250) += plat-serial8250.o diff --git a/arch/arm/mach-ns9xxx/cc9p9215_devices.c b/arch/arm/mach-ns9xxx/cc9p9215_devices.c new file mode 100644 index 000000000000..9de10e6e9666 --- /dev/null +++ b/arch/arm/mach-ns9xxx/cc9p9215_devices.c @@ -0,0 +1,681 @@ +/* + * arch/arm/mach-ns9xxx/cc9p9215_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/gpio.h> +#include <linux/mtd/physmap.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/delay.h> + +#include <mach/fim-ns921x.h> +#include <mach/hardware.h> +#include <mach/regs-sys-common.h> +#include <mach/regs-sys-ns921x.h> +#include <mach/regs-mem.h> + +#include <video/hx8347fb.h> +#include <linux/fb.h> +#include <linux/mmc/host.h> +#include <linux/w1-gpio.h> + +#include "ns921x_devices.h" +#include "cc9p9215_devices.h" +#include "clock.h" + +/* + * Pick Digi's internal FIM board + * Use internal board, defined to 1 + * Use newer boards, defined to 0 + */ +#if 0 +#define INT_FIM_BOARD +#endif + +#if defined(CONFIG_NS9XXX_ETH) || defined(CONFIG_NS9XXX_ETH_MODULE) +static int cc9p9215_phy_endisable(struct clk *clk, int enable) +{ + int ret; + + if (enable) { + ret = gpio_request(90, "ns9xxx-eth-phy"); + if (ret) + return ret; + + gpio_direction_output(90, 1); + } else { + gpio_set_value(90, 0); + gpio_free(90); + } + + return 0; +} + +static struct clk phyclk = { + .name = "ns9xxx-eth-phy", + .id = -1, + .owner = THIS_MODULE, + .endisable = cc9p9215_phy_endisable, +}; + +void __init ns9xxx_add_device_cc9p9215_eth(void) +{ + int gpio[] = {32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49}; + int func[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0}; + int dir[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + if (clk_register(&phyclk)) + return; + + ns9xxx_add_device_ns921x_eth(&phyclk, 0, gpio, func, + dir, ARRAY_SIZE(gpio)); +} +#else +void __init ns9xxx_add_device_cc9p9215_eth(void) {} +#endif + +#if defined(CONFIG_I2C_NS9XXX) || defined(CONFIG_I2C_NS9XXX_MODULE) +static void cc9p9215_i2c_gpio_reconfigure(void) +{ + gpio_configure_ns921x(102, 0, 0, 2, 0); + gpio_configure_ns921x(103, 0, 0, 2, 0); +} + +static struct plat_ns9xxx_i2c ns9xxx_device_cc9p9215_i2c_data = { + .gpio_scl = 102, + .gpio_sda = 103, + .speed = 100000, + .gpio_configuration_func = cc9p9215_i2c_gpio_reconfigure, +}; + +void __init ns9xxx_add_device_cc9p9215_i2c(void) +{ + ns9xxx_add_device_ns921x_i2c(&ns9xxx_device_cc9p9215_i2c_data); +} +#else +void __init ns9xxx_add_device_cc9p9215_i2c(void) {} +#endif + +#if defined(CONFIG_SERIAL_NS921X) || defined(CONFIG_SERIAL_NS921X_MODULE) +void __init ns9xxx_add_device_cc9p9215_uarta(int gpio_nr) +{ + ns9xxx_add_device_ns921x_uarta(0, gpio_nr, 0); +} + +void __init ns9xxx_add_device_cc9p9215_uartb(int gpio_nr) +{ + ns9xxx_add_device_ns921x_uartb(51, gpio_nr, 0); +} + +void __init ns9xxx_add_device_cc9p9215_uartc(int gpio_nr) +{ + ns9xxx_add_device_ns921x_uartc(8, gpio_nr, 0); +} + +void __init ns9xxx_add_device_cc9p9215_uartd(int gpio_nr) +{ + ns9xxx_add_device_ns921x_uartd(59, gpio_nr, 0); +} +#else +void __init ns9xxx_add_device_cc9p9215_uarta(int gpio_nr) {} +void __init ns9xxx_add_device_cc9p9215_uartb(int gpio_nr) {} +void __init ns9xxx_add_device_cc9p9215_uartc(int gpio_nr) {} +void __init ns9xxx_add_device_cc9p9215_uartd(int gpio_nr) {} +#endif + +#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP) +static struct physmap_flash_data ns9xxx_device_cc9p9215_flash_data = { + .width = 2, +}; + +void __init ns9xxx_add_device_cc9p9215_flash(void) +{ + ns9xxx_add_device_ns921x_flash(&ns9xxx_device_cc9p9215_flash_data); +} +#else +void __init ns9xxx_add_device_cc9p9215_flash(void) {} +#endif + +#if defined(CONFIG_SPI_NS921X) || defined(CONFIG_SPI_NS921X_MODULE) +/* SPI ports and their related GPIOs */ +static struct spi_ns9xxx_data ns9xxx_device_cc9p9215_spi_data = { + .gpios = {7, 3, 5, 0}, + .gpio_funcs = { NS921X_GPIO_FUNC_4, + NS921X_GPIO_FUNC_4, + NS921X_GPIO_FUNC_4, + NS921X_GPIO_FUNC_4 }, + .nr_gpios = 4, +}; + +void __init ns9xxx_add_device_cc9p9215_spi(void) { + ns9xxx_add_device_ns921x_spi(&ns9xxx_device_cc9p9215_spi_data); +} +#else +void __init ns9xxx_add_device_cc9p9215_spi(void) {} +#endif + + +#if defined(CONFIG_FIM_ZERO_SERIAL) +static struct fim_serial_platform_data fim_serial_data0 = { + .fim_nr = 0, +#if defined(CONFIG_FIM_ZERO_SERIAL_CTSRTS) + NS921X_FIM_SERIAL_GPIOS(69, 68, /* RX + TX */ + 70, 71, /* RTS + CTS */ + NS921X_GPIO_FUNC_0), +#else + NS921X_FIM_SERIAL_GPIOS(69, 68, /* RX + TX */ + FIM_GPIO_DONT_USE, /* RTS */ + FIM_GPIO_DONT_USE, /* CTS */ + NS921X_GPIO_FUNC_0), +#endif +}; +struct platform_device ns921x_fim_serial0 = { + .name = "fim-serial", + .id = 0, + .dev.platform_data = &fim_serial_data0, +}; +EXPORT_SYMBOL(ns921x_fim_serial0); +#endif /* CONFIG_FIM_ZERO_SERIAL */ + +#if defined(CONFIG_FIM_ONE_SERIAL) +static struct fim_serial_platform_data fim_serial_data1 = { + .fim_nr = 1, +#if defined(CONFIG_FIM_ONE_SERIAL_CTSRTS) + NS921X_FIM_SERIAL_GPIOS(73, 72, /* RX + TX */ + 74, 75, /* RTS + CTS */ + NS921X_GPIO_FUNC_1), +#else + NS921X_FIM_SERIAL_GPIOS(73, 72, /* RX + TX */ + FIM_GPIO_DONT_USE, /* RTS */ + FIM_GPIO_DONT_USE, /* CTS */ + NS921X_GPIO_FUNC_1), +#endif +}; +struct platform_device ns921x_fim_serial1 = { + .name = "fim-serial", + .id = 1, + .dev.platform_data = &fim_serial_data1, +}; +EXPORT_SYMBOL(ns921x_fim_serial1); +#endif /* CONFIG_FIM_ONE_SERIAL */ + + +#if defined(CONFIG_FIM_ZERO_SDIO) +static struct fim_sdio_platform_data fim_sdio_data0 = { + .fim_nr = 0, + .host_caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ, +#if defined(INT_FIM_BOARD) + NS921X_FIM_SDIO_GPIOS(68, 69, 70, 71, /* D0 to D3 */ + 72, 73, /* WP + CD */ + 76, 77, /* CLK + CMD */ + NS921X_GPIO_FUNC_0), +#else + NS921X_FIM_SDIO_GPIOS_FIM(68, 69, 70, 71, /* D0 to D3 */ + 76, 77, /* CLK + CMD */ + NS921X_GPIO_FUNC_0), + .cd_gpio_nr = 101, /* CD as external intrrupt */ + .cd_gpio_func = NS921X_GPIO_FUNC_2, + + .wp_gpio_nr = 100, /* WP as normal GPIO */ + .wp_gpio_func = NS921X_GPIO_FUNC_3, +#endif +}; +struct platform_device ns921x_fim_sdio0 = { + .name = "fim-sdio", + .id = 0, + .dev.platform_data = &fim_sdio_data0, +}; +EXPORT_SYMBOL(ns921x_fim_sdio0); +#endif /* CONFIG_FIM_ZERO_SDIO */ + + +#if defined(CONFIG_FIM_ONE_SDIO) +static struct fim_sdio_platform_data fim_sdio_data1 = { + .fim_nr = 1, + .host_caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ, +#if defined(INT_FIM_BOARD) + NS921X_FIM_SDIO_GPIOS(68, 69, 70, 71, /* D0 to D3 */ + 72, 73, /* WP + CD */ + 76, 77, /* CLK + CMD */ + NS921X_GPIO_FUNC_1), +#else + NS921X_FIM_SDIO_GPIOS_FIM(72, 73, 74, 75, /* D0 to D3 */ + 78, 79, /* CLK + CMD */ + NS921X_GPIO_FUNC_1), + .cd_gpio_nr = 101, /* CD as external intrrupt */ + .cd_gpio_func = NS921X_GPIO_FUNC_2, + + .wp_gpio_nr = 100, /* WP as normal GPIO */ + .wp_gpio_func = NS921X_GPIO_FUNC_3, +#endif +}; +struct platform_device ns921x_fim_sdio1 = { + .name = "fim-sdio", + .id = 1, + .dev.platform_data = &fim_sdio_data1, +}; +EXPORT_SYMBOL(ns921x_fim_sdio1); +#endif /* CONFIG_FIM_ONE_SDIO */ + + +#if defined(CONFIG_FIM_ZERO_CAN) || defined(CONFIG_PROCESSOR_NS9215) +static struct fim_can_platform_data fim_can_data0 = { + .fim_nr = 0, + .fim_can_bitrate = 500000, + NS921X_FIM_CAN_GPIOS( 96, 97, /* RX + TX */ + NS921X_GPIO_FUNC_2), +}; +struct platform_device ns921x_fim_can0 = { + .name = "fim-can", + .id = 0, + .dev.platform_data = &fim_can_data0, +}; +EXPORT_SYMBOL(ns921x_fim_can0); +#endif /* CONFIG_FIM_ZERO_CAN */ + +#if defined(CONFIG_FIM_ONE_CAN) +static struct fim_can_platform_data fim_can_data1 = { + .fim_nr = 1, + .fim_can_bitrate = 500000, +#if defined(INT_FIM_BOARD) + NS921X_FIM_CAN_GPIOS( 68, 69, /* RX + TX */ + NS921X_GPIO_FUNC_2), +#else + NS921X_FIM_CAN_GPIOS( 98, 99, /* RX + TX */ + NS921X_GPIO_FUNC_2), +#endif +}; +struct platform_device ns921x_fim_can1 = { + .name = "fim-can", + .id = 1, + .dev.platform_data = &fim_can_data1, +}; +EXPORT_SYMBOL(ns921x_fim_can1); +#endif /* CONFIG_FIM_ONE_CAN */ + +#if defined(CONFIG_FIM_ZERO_W1) +static struct w1_gpio_platform_data fim_w1_data0 = { + .pin = 68, + .is_open_drain = 0, +}; +struct platform_device ns921x_fim0_w1 = { + .name = "w1-gpio", + .id = 0, + .dev = { + .platform_data = &fim_w1_data0, + }, +}; +EXPORT_SYMBOL(ns921x_fim0_w1); +#endif /* CONFIG_FIM_ZERO_W1 */ + +#if defined(CONFIG_FIM_ONE_W1) +static struct w1_gpio_platform_data fim_w1_data1 = { + .pin = 72, + .is_open_drain = 0, +}; +struct platform_device ns921x_fim1_w1 = { + .name = "w1-gpio", + .id = 1, + .dev = { + .platform_data = &fim_w1_data1, + }, +}; +EXPORT_SYMBOL(ns921x_fim1_w1); +#endif /* CONFIG_FIM_ONE_W1 */ + +#if defined(CONFIG_FIM_ZERO_USB) +static struct fim_usb_platform_data fim_usb_data0 = { + .fim_nr = 0, + + /* The setup of the pull-ups must be fixed in the driver, however print a warning */ +#if defined(INT_FIM_BOARD) +#warning "Internal FIM board has a different pull-ups configuration" + NS921X_FIM_USB_GPIOS(68, 69, 70, 71, /* VP + VM + RCV + OE_L */ + 72, 73, /* ENUM + SPND */ + NS921X_GPIO_FUNC_0, + NS921X_GPIO_FUNC_GPIO), +#else + NS921X_FIM_USB_GPIOS(68, 69, 70, 71, /* VP + VM + RCV + OE_L */ + 76, 77, /* ENUM + SPND */ + NS921X_GPIO_FUNC_0, + NS921X_GPIO_FUNC_GPIO), +#endif +}; +struct platform_device ns921x_fim_usb0 = { + .name = "fim-usb", + .id = 0, + .dev.platform_data = &fim_usb_data0, +}; +EXPORT_SYMBOL(ns921x_fim_usb0); +#endif /* CONFIG_FIM_ZERO_USB */ + +#if defined(CONFIG_FIM_ONE_USB) +static struct fim_usb_platform_data fim_usb_data1 = { + .fim_nr = 1, + NS921X_FIM_USB_GPIOS(72, 73, 74, 75, /* VP + VM + RCV + OE_L */ + 78, 79, /* ENUM + SPND */ + NS921X_GPIO_FUNC_1, + NS921X_GPIO_FUNC_GPIO), +}; +struct platform_device ns921x_fim_usb1 = { + .name = "fim-usb", + .id = 1, + .dev.platform_data = &fim_usb_data1, +}; +EXPORT_SYMBOL(ns921x_fim_usb1); +#endif /* CONFIG_FIM_ONE_USB */ + +#if defined(CONFIG_CC9P9215JS_EDT_DISPLAY_QVGA) +#ifdef CONFIG_CC9P9215JS_DISPLAY_USES_DMA +#include <mach/dma-ns921x.h> +struct ext_dma_desc_t dmadesc[3]; +#endif + +void __init cc9p9215_edt_qvga_lcd_setup_cs(void) +{ + /* LCD required the extended wait register to be set */ + writel(3, MEM_SMEW); + /* 16 bit bus width and enable exteneded wait */ + writel(MEM_SMC_PB_1 | MEM_SMC_EW_ON | MEM_SMC_MW_16, MEM_SMC(0)); + /* Static Memory Write Enable Delay x */ + writel(4, MEM_SMWED(0)); + /* Static Memory Output Enable Delay x */ + writel(0, MEM_SMOED(0)); + /* Static Memory Read Delay x */ + writel(0, MEM_SMRD(0)); + /* Static Memory Page Mode Read Delay 0 */ + writel(0, MEM_SMPMRD(0)); + /* Static Memory Write Delay */ + writel(0, MEM_SMWD(0)); + /* Static Memory Turn Round Delay x */ + writel(0, MEM_SWT(0)); + /* Enable the CS0 access */ + writel(readl(SYS_SMCSSMM(0)) | SYS_SMCSSMM_CSEx_EN, SYS_SMCSSMM(0)); +} + + +int cc9p9215_edt_qvga_lcd_register_gpios(struct hx8347fb_pdata *pdata) +{ + if (gpio_request(pdata->rst_gpio, "lcd-rst")) + goto err; + + gpio_direction_output(pdata->rst_gpio, 0); + + if (gpio_request(pdata->enable_gpio, "lcd-enable")) + goto err1; + + gpio_direction_output(pdata->enable_gpio, 0); + + return 0; +err1: + gpio_free(pdata->rst_gpio); +err: + return -EBUSY; +} + +/* Configuration for the EDT QVGA display, most of the settings have + * been taken from a Himax application note */ +unsigned char edt_qvga_lcd_init[][3] = { + /* Index, value, delay to write next register in ms*/ + {0x46, 0x94, 0}, + {0x47, 0x41, 0}, + {0x48, 0x00, 0}, + {0x49, 0x33, 0}, + {0x4a, 0x23, 0}, + {0x4b, 0x45, 0}, + {0x4c, 0x44, 0}, + {0x4d, 0x77, 0}, + {0x4e, 0x12, 0}, + {0x4f, 0xcc, 0}, + {0x50, 0x46, 0}, + {0x51, 0x82, 0}, + {0x02, 0x00, 0}, /* Column address start 2 */ + {0x03, 0x00, 0}, /* Column address start 1 */ + {0x04, 0x01, 0}, /* Column address end 2 */ + {0x05, 0x3f, 0}, /* Column address end 1 */ + {0x06, 0x00, 0}, /* Row address start 2 */ + {0x07, 0x00, 0}, /* Row address start 1 */ + {0x08, 0x00, 0}, /* Row address end 2 */ + {0x09, 0xef, 0}, /* Row address end 1 */ + {0x01, 0x06, 0}, + {0x16, 0x68, 0}, + {0x23, 0x95, 0}, + {0x24, 0x95, 0}, + {0x25, 0xff, 0}, + {0x27, 0x02, 0}, + {0x28, 0x02, 0}, + {0x29, 0x02, 0}, + {0x2a, 0x02, 0}, + {0x2c, 0x02, 0}, + {0x2d, 0x02, 0}, + {0x3a, 0x01, 0}, + {0x3b, 0x01, 0}, + {0x3c, 0xf0, 0}, + {0x3d, 0x00, 20}, + {0x35, 0x38, 0}, + {0x36, 0x78, 0}, + {0x3e, 0x38, 0}, + {0x40, 0x0f, 0}, + {0x41, 0xf0, 0}, + {0x19, 0x49, 0}, + {0x93, 0x0f, 10}, + {0x20, 0x40, 0}, + {0x1d, 0x07, 0}, + {0x1e, 0x00, 0}, + {0x1f, 0x04, 0}, + {0x44, 0x40, 0}, + {0x45, 0x12, 10}, + {0x1c, 0x04, 20}, + {0x43, 0x80, 5}, + {0x1b, 0x08, 40}, + {0x1b, 0x10, 40}, + {0x90, 0x7f, 0}, + {0x26, 0x04, 40}, + {0x26, 0x24, 0}, + {0x26, 0x2c, 40}, + {0x26, 0x3c, 0}, + {0x57, 0x02, 0}, + {0x55, 0x00, 0}, + {0x57, 0x00, 0} +}; + + +static void cc9p9215_lcd_reset(struct hx8347fb_par *par) +{ + gpio_set_value(par->pdata->rst_gpio, 0); + mdelay(100); + gpio_set_value(par->pdata->rst_gpio, 1); +} + +static void cc9p9215_lcd_enable(struct hx8347fb_par *par, int state) +{ + gpio_set_value(par->pdata->enable_gpio, state); +} + +static void cc9p9215_lcd_set_idx(struct hx8347fb_par *par, u8 idx) +{ + writeb(idx, par->mmio_cmd); +} + +static void cc9p9215_lcd_wr_reg(struct hx8347fb_par *par, u8 reg, u16 data) +{ + writeb(reg, par->mmio_cmd); + writew(data, par->mmio_data); +} + +#ifdef CONFIG_CC9P9215JS_DISPLAY_USES_DMA +static irqreturn_t fb_extdma(int irq, void *dev_id) +{ + u32 status; + + status = readl(NS921X_DMA_STIE(1)); + + if (status & (NS921X_DMA_STIE_NCIP | NS921X_DMA_STIE_NRIP)) { + writel(status, NS921X_DMA_STIE(1)); + } + + return IRQ_HANDLED; +} +#endif + +static void cc9p9215_lcd_wr_data(struct hx8347fb_par *par, u16 *buf, int len) +{ +#ifdef CONFIG_CC9P9215JS_DISPLAY_USES_DMA +#if 0 + /* CE=0, CG=1, SW=16bit, DW=16bit, SB=16 bytes, DB=1 unit, SAI=0, DAI=1 */ + writel(NS921X_DMA_CR_CG | NS921X_DMA_CR_SW_16b | \ + NS921X_DMA_CR_DW_16b | NS921X_DMA_CR_SB_16B | \ + NS921X_DMA_CR_DB_1B | NS921X_DMA_CR_DINC_N, NS921X_DMA_CR(1)); + /* CE=1, CG=1, SW=16bit, DW=16bit, SB=16 bytes, DB=1 unit, SAI=0, DAI=1 */ + writel(NS921X_DMA_CR_CE | readl(NS921X_DMA_CR(1)), NS921X_DMA_CR(1));*/*/*/ +#endif +#else + int i, wcycles; + u16 *data = buf; + + wcycles = len >> 1; + + for (i = 0; i < wcycles; i++) + writew(*data++, par->mmio_data); +#endif +} + +static int cc9p9215_lcd_init(struct hx8347fb_par *par) +{ + int i, ret = 0; + u8 reg; + + if (cc9p9215_edt_qvga_lcd_register_gpios(par->pdata)) + return -EINVAL; + + cc9p9215_lcd_enable(par, 0); + cc9p9215_lcd_reset(par); + cc9p9215_edt_qvga_lcd_setup_cs(); + + mdelay(50); + + writeb(HIMAX_ID_CODE, par->mmio_cmd); + if ((reg = readb(par->mmio_data)) != 0x47) { + pr_debug("%s: HX8347 controller not detected REG[0x67] = 0x%02x\n", __func__, reg); + ret = -EIO; + goto err_detect; + } + +#ifdef CONFIG_CC9P9215JS_DISPLAY_USES_DMA + writel(SYS_CLOCK_EXTDMA | readl(SYS_RESET), SYS_RESET); + writel(SYS_CLOCK_EXTDMA | readl(SYS_CLOCK), SYS_CLOCK); + + dmadesc[0].src = (u32)par->info->screen_base; + dmadesc[0].dest = (u32)par->info->fix.smem_start; + dmadesc[0].length = (u16)(par->info->fix.smem_len / 3); + dmadesc[0].control = EXT_DMA_DESC_CTRL_FULL; + + dmadesc[1].src = (u32)(par->info->screen_base + par->info->fix.smem_len / 3); + dmadesc[1].dest = (u32)par->info->fix.smem_start; + dmadesc[1].length = (u16)(par->info->fix.smem_len / 3); + dmadesc[1].control = EXT_DMA_DESC_CTRL_FULL; + + dmadesc[2].src = (u32)(dmadesc[1].src + par->info->fix.smem_len / 3); + dmadesc[2].dest = (u32)par->info->fix.smem_start; + dmadesc[2].length = (u16)(par->info->fix.smem_len / 3); + dmadesc[2].control = EXT_DMA_DESC_CTRL_WRAP | \ + EXT_DMA_DESC_CTRL_LAST | \ + EXT_DMA_DESC_CTRL_FULL; + + /* Setup the DMA Controllers */ + writel(&dmadesc[0], NS921X_DMA_BDP(1)); + writel(NS921X_DMA_STIE_NCIE | NS921X_DMA_STIE_ECIE | \ + NS921X_DMA_STIE_NRIE | NS921X_DMA_STIE_CAIE, NS921X_DMA_STIE(1)); + + ret = request_irq(IRQ_NS921X_EXTDMA, fb_extdma, 0, "fb_extdma", NULL); + if (ret) { + pr_debug("%s: err_request_irq_extdmairq %d -> %d\n", __func__, IRQ_NS921X_EXTDMA, ret); + return ret; + } +#endif + + for (i=0; i < (sizeof(edt_qvga_lcd_init)/3); i++) { + + cc9p9215_lcd_wr_reg(par, edt_qvga_lcd_init[i][0], + edt_qvga_lcd_init[i][1]); + mdelay(edt_qvga_lcd_init[i][2]); + } + + return 0; + +err_detect: + gpio_free(par->pdata->rst_gpio); + gpio_free(par->pdata->enable_gpio); + + return ret; +} + +static void cc9p9215_lcd_cleanup(struct hx8347fb_par *par) +{ + gpio_direction_input(par->pdata->rst_gpio); + gpio_direction_input(par->pdata->enable_gpio); + gpio_free(par->pdata->rst_gpio); + gpio_free(par->pdata->enable_gpio); +} + +static struct resource cc9p9215js_lcd_res[] = { + { + .start = 0x40000000, + .end = 0x40000001, + .flags = IORESOURCE_MEM, + }, { + .start = 0x40000002, + .end = 0x40000003, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_NS921X_EXTDMA, + .flags = IORESOURCE_IRQ, + } +}; + +static struct hx8347fb_pdata c9p9215js_lcd_pdata = { + .owner = THIS_MODULE, + .reset = cc9p9215_lcd_reset, + .bl_enable = cc9p9215_lcd_enable, + .init = cc9p9215_lcd_init, + .cleanup = cc9p9215_lcd_cleanup, + .set_idx = cc9p9215_lcd_set_idx, + .wr_reg = cc9p9215_lcd_wr_reg, + .wr_data = cc9p9215_lcd_wr_data, + .rst_gpio = 86, + .enable_gpio = 87, + .usedma = 0, + .xres = 320, + .yres = 240, + .bits_per_pixel = 16, +}; + +static struct platform_device edt_qvga_lcd = { + .name = "hx8347", + .id = 0, + .dev = { + .platform_data = &c9p9215js_lcd_pdata, + }, + .resource = cc9p9215js_lcd_res, + .num_resources = ARRAY_SIZE(cc9p9215js_lcd_res), +}; + +void __init ns9xxx_add_device_cc9p9215_edt_diplay(void) +{ + platform_device_register(&edt_qvga_lcd); +} +#else +void __init ns9xxx_add_device_cc9p9215_edt_diplay(void) {} +#endif + diff --git a/arch/arm/mach-ns9xxx/cc9p9215_devices.h b/arch/arm/mach-ns9xxx/cc9p9215_devices.h new file mode 100644 index 000000000000..916815b3a484 --- /dev/null +++ b/arch/arm/mach-ns9xxx/cc9p9215_devices.h @@ -0,0 +1,45 @@ +/* + * arch/arm/mach-ns9xxx/cc9p9215_devices.h + * + * 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. + */ + +void __init ns9xxx_add_device_cc9p9215_eth(void); +void __init ns9xxx_add_device_cc9p9215_i2c(void); +void __init ns9xxx_add_device_cc9p9215_uarta(int gpio_start); +void __init ns9xxx_add_device_cc9p9215_uartb(int gpio_start); +void __init ns9xxx_add_device_cc9p9215_uartc(int gpio_start); +void __init ns9xxx_add_device_cc9p9215_uartd(int gpio_start); +void __init ns9xxx_add_device_cc9p9215_flash(void); +void __init ns9xxx_add_device_cc9p9215_spi(void); +void __init ns9xxx_add_device_cc9p9215_edt_diplay(void); + +#define ns9xxx_add_device_cc9p9215_uarta_rxtx() \ + ns9xxx_add_device_cc9p9215_uarta(2) +#define ns9xxx_add_device_cc9p9215_uarta_ctsrtsrxtx() \ + ns9xxx_add_device_cc9p9215_uarta(4) +#define ns9xxx_add_device_cc9p9215_uarta_full() \ + ns9xxx_add_device_cc9p9215_uarta(8) +#define ns9xxx_add_device_cc9p9215_uartb_rxtx() \ + ns9xxx_add_device_cc9p9215_uartb(2) +#define ns9xxx_add_device_cc9p9215_uartb_ctsrtsrxtx() \ + ns9xxx_add_device_cc9p9215_uartb(4) +#define ns9xxx_add_device_cc9p9215_uartb_full() \ + ns9xxx_add_device_cc9p9215_uartb(8) +#define ns9xxx_add_device_cc9p9215_uartc_rxtx() \ + ns9xxx_add_device_cc9p9215_uartc(2) +#define ns9xxx_add_device_cc9p9215_uartc_ctsrtsrxtx() \ + ns9xxx_add_device_cc9p9215_uartc(4) +#define ns9xxx_add_device_cc9p9215_uartc_full() \ + ns9xxx_add_device_cc9p9215_uartc(8) +#define ns9xxx_add_device_cc9p9215_uartd_rxtx() \ + ns9xxx_add_device_cc9p9215_uartd(2) +#define ns9xxx_add_device_cc9p9215_uartd_ctsrtsrxtx() \ + ns9xxx_add_device_cc9p9215_uartd(4) +#define ns9xxx_add_device_cc9p9215_uartd_full() \ + ns9xxx_add_device_cc9p9215_uartd(8) diff --git a/arch/arm/mach-ns9xxx/cc9p9360_devices.c b/arch/arm/mach-ns9xxx/cc9p9360_devices.c new file mode 100644 index 000000000000..12ebf16818f8 --- /dev/null +++ b/arch/arm/mach-ns9xxx/cc9p9360_devices.c @@ -0,0 +1,232 @@ +/* + * arch/arm/mach-ns9xxx/cc9p9360_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/gpio.h> +#include <linux/platform_device.h> + +#include "ns9360_devices.h" +#include "cc9p9360_devices.h" + + +#if defined(CONFIG_MTD_NAND_CCX9X) || defined(CONFIG_MTD_NAND_CCX9X_MODULE) +static struct ccx9x_nand_info ns9xxx_device_cc9p9360_nand_data = { + .addr_offset = 0x2000, + .cmd_offset = 0x4000, + .delay = 25, + .busy_pin = 49, +}; +void __init ns9xxx_add_device_cc9p9360_nand(void) +{ + ns9xxx_add_device_ns9360_nand(&ns9xxx_device_cc9p9360_nand_data); +} +#else +void __init ns9xxx_add_device_cc9p9360_nand(void) {} +#endif + +#if defined(CONFIG_I2C_NS9XXX) || defined(CONFIG_I2C_NS9XXX_MODULE) +static void cc9p9360_i2c_gpio_reconfigure(void) +{ + gpio_configure_ns9360(70, 0, 0, 2); + gpio_configure_ns9360(71, 0, 0, 2); +} + +static struct plat_ns9xxx_i2c ns9xxx_device_cc9p9360_i2c_data = { + .gpio_scl = 70, + .gpio_sda = 71, + .speed = 100000, + .gpio_configuration_func = cc9p9360_i2c_gpio_reconfigure, +}; + +void __init ns9xxx_add_device_cc9p9360_i2c(void) +{ + ns9xxx_add_device_ns9360_i2c(&ns9xxx_device_cc9p9360_i2c_data); +} +#else +void __init ns9xxx_add_device_cc9p9360_i2c(void) {} +#endif + +#if defined(CONFIG_SERIAL_NS9360) || defined(CONFIG_SERIAL_NS9360_MODULE) +void __init ns9xxx_add_device_cc9p9360_uarta_rxtx(void) +{ + int uarta_gpio[] = {8, 9}; + ns9xxx_add_device_ns9360_uarta(uarta_gpio, ARRAY_SIZE(uarta_gpio), 0); +} + +void __init ns9xxx_add_device_cc9p9360_uarta_ctsrtsrxtx(void) +{ + int uarta_gpio[] = {8, 9, 10, 11}; + ns9xxx_add_device_ns9360_uarta(uarta_gpio, ARRAY_SIZE(uarta_gpio), 0); +} + +void __init ns9xxx_add_device_cc9p9360_uarta_full(void) +{ + int uarta_gpio[] = {8, 9, 10, 11, 12, 13, 14, 15}; + ns9xxx_add_device_ns9360_uarta(uarta_gpio, ARRAY_SIZE(uarta_gpio), 0); +} + +void __init ns9xxx_add_device_cc9p9360_uartb_rxtx(void) +{ + int uartb_gpio[] = {0, 1}; + ns9xxx_add_device_ns9360_uartb(uartb_gpio, ARRAY_SIZE(uartb_gpio), 0); +} + +void __init ns9xxx_add_device_cc9p9360_uartb_ctsrtsrxtx(void) +{ + int uartb_gpio[] = {0, 1, 2, 3}; + ns9xxx_add_device_ns9360_uartb(uartb_gpio, ARRAY_SIZE(uartb_gpio), 0); +} + +void __init ns9xxx_add_device_cc9p9360_uartb_full(void) +{ + int uartb_gpio[] = {0, 1, 2, 3, 4, 5, 6, 7}; + ns9xxx_add_device_ns9360_uartb(uartb_gpio, ARRAY_SIZE(uartb_gpio), 0); +} + +void __init ns9xxx_add_device_cc9p9360_uartc_rxtx(void) +{ + int uartc_gpio[] = {40, 41}; + ns9xxx_add_device_ns9360_uartc(uartc_gpio, ARRAY_SIZE(uartc_gpio), 0); +} + +void __init ns9xxx_add_device_cc9p9360_uartc_ctsrtsrxtx(void) +{ + int uartc_gpio[] = {40, 41, 42, 43}; + ns9xxx_add_device_ns9360_uartc(uartc_gpio, ARRAY_SIZE(uartc_gpio), 0); +} + +void __init ns9xxx_add_device_cc9p9360_uartc_full(void) +{ + int uartc_gpio[] = {40, 41, 42, 43, 20, 21, 22, 23}; + ns9xxx_add_device_ns9360_uartc(uartc_gpio, ARRAY_SIZE(uartc_gpio), 0); +} + +void __init ns9xxx_add_device_cc9p9360_uartd_rxtx(void) +{ + int uartd_gpio[] = {44, 45}; + ns9xxx_add_device_ns9360_uartd(uartd_gpio, ARRAY_SIZE(uartd_gpio), 0); +} + +void __init ns9xxx_add_device_cc9p9360_uartd_ctsrtsrxtx(void) +{ + int uartd_gpio[] = {44, 45, 46, 47}; + ns9xxx_add_device_ns9360_uartd(uartd_gpio, ARRAY_SIZE(uartd_gpio), 0); +} + +void __init ns9xxx_add_device_cc9p9360_uartd_full(void) +{ + int uartd_gpio[] = {44, 45, 46, 47, 24, 25, 26, 27}; + ns9xxx_add_device_ns9360_uartd(uartd_gpio, ARRAY_SIZE(uartd_gpio), 0); +} +#else +void __init ns9xxx_add_device_cc9p9360_uarta_rxtx(void) {} +void __init ns9xxx_add_device_cc9p9360_uarta_ctsrtsrxtx(void) {} +void __init ns9xxx_add_device_cc9p9360_uarta_full(void) {} +void __init ns9xxx_add_device_cc9p9360_uartb_rxtx(void) {} +void __init ns9xxx_add_device_cc9p9360_uartb_ctsrtsrxtx(void) {} +void __init ns9xxx_add_device_cc9p9360_uartb_full(void) {} +void __init ns9xxx_add_device_cc9p9360_uartc_rxtx(void) {} +void __init ns9xxx_add_device_cc9p9360_uartc_ctsrtsrxtx(void) {} +void __init ns9xxx_add_device_cc9p9360_uartc_full(void) {} +void __init ns9xxx_add_device_cc9p9360_uartd_rxtx(void) {} +void __init ns9xxx_add_device_cc9p9360_uartd_ctsrtsrxtx(void) {} +void __init ns9xxx_add_device_cc9p9360_uartd_full(void) {} +#endif + +#if defined(CONFIG_FB_NS9360) || defined(CONFIG_FB_NS9360_MODULE) +void __init ns9xxx_add_device_cc9p9360_fb(int power) +{ + int gpio[] = {19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41}; + int func[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; + + ns9xxx_add_device_ns9360_fb(gpio, ARRAY_SIZE(gpio), func, power); +} +#else +void __init ns9xxx_add_device_cc9p9360_fb(int power) {} +#endif + +#if defined(CONFIG_SPI_NS9360) || defined(CONFIG_SPI_NS9360_MODULE) +/* SPI ports and their related GPIOs */ +static struct spi_ns9xxx_data ns9xxx_device_cc9p9360_spi_porta_data = { + .gpios = {8, 9, 14, 15}, + .gpio_funcs = { NS9360_GPIO_FUNC_0, + NS9360_GPIO_FUNC_0, + NS9360_GPIO_FUNC_0, + NS9360_GPIO_FUNC_0 }, + .nr_gpios = 4, +}; + +static struct spi_ns9xxx_data ns9xxx_device_cc9p9360_spi_portb_data = { + .gpios = {0, 1, 6, 7}, + .gpio_funcs = { NS9360_GPIO_FUNC_0, + NS9360_GPIO_FUNC_0, + NS9360_GPIO_FUNC_0, + NS9360_GPIO_FUNC_0 }, + .nr_gpios = 4, +}; + +static struct spi_ns9xxx_data ns9xxx_device_cc9p9360_spi_portc_data = { + .gpios = {40, 41, 22, 23}, + .gpio_funcs = { NS9360_GPIO_FUNC_0, + NS9360_GPIO_FUNC_0, + NS9360_GPIO_FUNC_0, + NS9360_GPIO_FUNC_0 }, + .nr_gpios = 4, +}; + +static struct spi_ns9xxx_data ns9xxx_device_cc9p9360_spi_portd_data = { + .gpios = {44, 45, 26, 27}, + .gpio_funcs = { NS9360_GPIO_FUNC_0, + NS9360_GPIO_FUNC_0, + NS9360_GPIO_FUNC_0, + NS9360_GPIO_FUNC_0 }, + .nr_gpios = 4, +}; + +void __init ns9xxx_add_device_cc9p9360_spi_porta(void) +{ + ns9xxx_add_device_ns9360_spi_porta( &ns9xxx_device_cc9p9360_spi_porta_data ); +} + +void __init ns9xxx_add_device_cc9p9360_spi_portb(void) +{ + ns9xxx_add_device_ns9360_spi_portb( &ns9xxx_device_cc9p9360_spi_portb_data ); +} + +void __init ns9xxx_add_device_cc9p9360_spi_portc(void) +{ + ns9xxx_add_device_ns9360_spi_portc( &ns9xxx_device_cc9p9360_spi_portc_data ); +} + +void __init ns9xxx_add_device_cc9p9360_spi_portd(void) +{ + ns9xxx_add_device_ns9360_spi_portd( &ns9xxx_device_cc9p9360_spi_portd_data ); +} + +#else +void __init ns9xxx_add_device_cc9p9360_spi_porta(void) {} +void __init ns9xxx_add_device_cc9p9360_spi_portb(void) {} +void __init ns9xxx_add_device_cc9p9360_spi_portc(void) {} +void __init ns9xxx_add_device_cc9p9360_spi_portd(void) {} +#endif + +#if defined(CONFIG_NS9XXX_ETH) || defined(CONFIG_NS9XXX_ETH_MODULE) +void __init ns9xxx_add_device_cc9p9360_eth(void) +{ + int gpio[] = {50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65}; + + ns9xxx_add_device_ns9360_eth(gpio, 16, 0, 0xfffffffd); +} +#else +void __init ns9xxx_add_device_cc9p9360_eth(void) {} +#endif diff --git a/arch/arm/mach-ns9xxx/cc9p9360_devices.h b/arch/arm/mach-ns9xxx/cc9p9360_devices.h new file mode 100644 index 000000000000..2c87238e2f4b --- /dev/null +++ b/arch/arm/mach-ns9xxx/cc9p9360_devices.h @@ -0,0 +1,32 @@ +/* + * arch/arm/mach-ns9xxx/cc9p9360_devices.h + * + * 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. + */ + +void __init ns9xxx_add_device_cc9p9360_nand(void); +void __init ns9xxx_add_device_cc9p9360_i2c(void); +void __init ns9xxx_add_device_cc9p9360_uarta_rxtx(void); +void __init ns9xxx_add_device_cc9p9360_uartb_rxtx(void); +void __init ns9xxx_add_device_cc9p9360_uartc_rxtx(void); +void __init ns9xxx_add_device_cc9p9360_uartd_rxtx(void); +void __init ns9xxx_add_device_cc9p9360_uarta_ctsrtsrxtx(void); +void __init ns9xxx_add_device_cc9p9360_uartb_ctsrtsrxtx(void); +void __init ns9xxx_add_device_cc9p9360_uartc_ctsrtsrxtx(void); +void __init ns9xxx_add_device_cc9p9360_uartd_ctsrtsrxtx(void); +void __init ns9xxx_add_device_cc9p9360_uarta_full(void); +void __init ns9xxx_add_device_cc9p9360_uartb_full(void); +void __init ns9xxx_add_device_cc9p9360_uartc_full(void); +void __init ns9xxx_add_device_cc9p9360_uartd_full(void); +void __init ns9xxx_add_device_cc9p9360_fb(int power); +void __init ns9xxx_add_device_cc9p9360_spi_porta(void); +void __init ns9xxx_add_device_cc9p9360_spi_portb(void); +void __init ns9xxx_add_device_cc9p9360_spi_portc(void); +void __init ns9xxx_add_device_cc9p9360_spi_portd(void); +void __init ns9xxx_add_device_cc9p9360_eth(void); +void __init ns9xxx_add_device_cc9p9360_touch(void); diff --git a/arch/arm/mach-ns9xxx/ccw9p9215_devices.c b/arch/arm/mach-ns9xxx/ccw9p9215_devices.c new file mode 100644 index 000000000000..d5630571d59d --- /dev/null +++ b/arch/arm/mach-ns9xxx/ccw9p9215_devices.c @@ -0,0 +1,379 @@ +/* + * arch/arm/mach-ns9xxx/cc9p9215_devices.c + * + * Copyright (C) 2009 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/gpio.h> +#include <linux/mtd/physmap.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/delay.h> + +#include <mach/fim-ns921x.h> +#include <mach/hardware.h> + +#include <mach/regs-sys-common.h> +#include <mach/regs-sys-ns921x.h> +#include <mach/regs-mem.h> + +#include <asm/leds.h> + +#include "pipermain.h" +#include "mac.h" +#include "airoha.h" + +/* + * Pick Digi's internal FIM board + * Use internal board, defined to 1 + * Use newer boards, defined to 0 + */ +#if defined(CONFIG_DIGI_PIPER_WIFI) + +/* Low level functions to access piper chip */ +static u32 read_reg(struct piper_priv *piperp, u8 reg) +{ + return ioread32(piperp->vbase + reg); +} + +static int write_reg(struct piper_priv *piperp, u8 reg, u32 val, reg_op_t op) +{ + unsigned long flags; + + spin_lock_irqsave(&piperp->ac->reg_lock, flags); + switch (op) { + case op_write: + iowrite32(val, piperp->vbase + reg); + break; + case op_or: + iowrite32(val | ioread32(piperp->vbase + reg), piperp->vbase + reg); + break; + case op_and: + iowrite32(val & ioread32(piperp->vbase + reg), piperp->vbase + reg); + break; + default: + printk(KERN_WARNING PIPER_DRIVER_NAME + ": Invalid write register operation (%d)\n", op); + WARN_ON(1); + break; + } + spin_unlock_irqrestore(&piperp->ac->reg_lock, flags); + + return 0; +} + +/* + * This macro waits for the AES busy bit to clear if we are writing to the + * AES FIFO. + */ +#define wait_for_aes_ready() while ((addr == BB_AES_FIFO) \ + && ((ioread32(piperp->vbase + BB_RSSI) \ + & BB_RSSI_EAS_FIFO_FULL) != 0)) { \ + udelay(1); \ + } + +static int write_fifo(struct piper_priv *piperp, u8 addr, u8 *buf, int len) +{ + int wordIndex; + int wordLength = len / sizeof(unsigned int); + unsigned long flags; + bool loadingBeacon = (addr == BEACON_FIFO); + + spin_lock_irqsave(&piperp->ac->reg_lock, flags); + + if (loadingBeacon) { + /* + * If we are loading a new beacon, then adjust the address to point + * to the data FIFO, and set the beacon enable bit which tells piper + * to put this data into the beacon buffer. + */ + addr = BB_DATA_FIFO; + iowrite32(ioread32(piperp->vbase + BB_GENERAL_CTL) | BB_GENERAL_CTL_BEACON_EN, + piperp->vbase + BB_GENERAL_CTL); + } + + if (((unsigned)(buf) & 0x3) == 0) { + /* + * We come here if the data is 32-bit aligned. We can dispense + * with memcpys + */ + if (wordLength == 1) { + /* + * Only 1 word of data, so just one write. + */ + unsigned int *word = (unsigned int *)buf; + + wait_for_aes_ready(); + iowrite32(cpu_to_be32(*word), piperp->vbase + addr); + len -= 4; + } else { + /* + * More than one word of data, so set up a for loop. + */ + for (wordIndex = 0; wordIndex < wordLength; wordIndex++) { + unsigned int *word = (unsigned int *)buf; + + wait_for_aes_ready(); + iowrite32(cpu_to_be32(word[wordIndex]), piperp->vbase + addr); + len -= 4; + } + } + } else { + /* + * Ugh! Data is not 32-bit aligned. We have to memcpy it! + */ + for (wordIndex = 0; wordIndex < wordLength; wordIndex++) { + unsigned int word; + + memcpy(&word, &buf[wordIndex * sizeof(unsigned int)], + sizeof(unsigned int)); + + wait_for_aes_ready(); + iowrite32(cpu_to_be32(word), piperp->vbase + addr); + len -= 4; + } + } + + if (len) { + /* + * Double Ugh! There was left over data at the end. We have to write + * the leftover data into the upper bytes of the last word, making + * sure the unused bytes are set to zero. + */ + unsigned int word; + + memcpy(&word, &buf[wordLength * sizeof(unsigned int)], sizeof(unsigned int)); + word = cpu_to_be32(word); + switch (len) { + case 1: + word &= 0xff000000; + break; + case 2: + word &= 0xffff0000; + break; + case 3: + word &= 0xffffff00; + break; + default: + printk(KERN_WARNING PIPER_DRIVER_NAME + ": len = %d at end of piper_write\n", len); + break; + } + wait_for_aes_ready(); + iowrite32(word, piperp->vbase + addr); + } + + if (loadingBeacon) { + /* + * If we just loaded a beacon, then don't forget to turn off the + * load beacon bit. + */ + iowrite32(ioread32(piperp->vbase + BB_GENERAL_CTL) & ~BB_GENERAL_CTL_BEACON_EN, + piperp->vbase + BB_GENERAL_CTL); + piperp->beacon.loaded = true; + } + + spin_unlock_irqrestore(&piperp->ac->reg_lock, flags); + + return 0; +} + +/* + * This routine waits for the empty flag to clear when we are reading from + * the AES FIFO. + */ +#define wait_for_aes_not_empty() \ + while ((addr == BB_AES_FIFO) \ + && ((ioread32(piperp->vbase + BB_RSSI) & BB_RSSI_EAS_FIFO_EMPTY) != 0)) { \ + udelay(1); \ + if (--timeout == 0) { \ + timeout = 10000; \ + } \ + } + +static int read_fifo(struct piper_priv *piperp, u8 addr, u8 *buf, int len) +{ + int wordIndex; + unsigned long flags; + int timeout = 10000; + + spin_lock_irqsave(&piperp->ac->reg_lock, flags); + + /* + * We can only read 32-bit words, so round the length up to an even multiple of + * 4 if necessary. + */ + len += 3; + len &= 0xfffffc; + + if ((len == 4) && ((((unsigned)buf) & 0x3) == 0)) { + unsigned *word = (unsigned *)buf; + + wait_for_aes_not_empty(); + *word = be32_to_cpu(ioread32(piperp->vbase + addr)); + } else if ((((unsigned)buf) & 0x3) == 0) { + unsigned *word = (unsigned *)buf; + + for (wordIndex = 0; wordIndex < (len / sizeof(unsigned)); wordIndex++) { + wait_for_aes_not_empty(); + word[wordIndex] = be32_to_cpu(ioread32(piperp->vbase + addr)); + } + } else { + /* + * If we come here, then the buffer is not aligned and we have to + * memcpy the data. + */ + for (wordIndex = 0; wordIndex < (len / sizeof(unsigned)); wordIndex++) { + unsigned word; + + wait_for_aes_not_empty(); + word = be32_to_cpu(ioread32(piperp->vbase + addr)); + memcpy(&buf[wordIndex * sizeof(unsigned)], &word, sizeof(word)); + } + } + spin_unlock_irqrestore(&piperp->ac->reg_lock, flags); + + return 0; +} + +/* Initialize piper hardware, mac and dsp firmwares and mac address */ +static int piper_init_chip_hw(struct piper_priv *piperp) +{ + int ret; + + piper_load_mac_firmware(piperp); + piper_load_dsp_firmware(piperp); + + ret = piper_spike_suppression(piperp, true); + if (ret) { + printk(KERN_WARNING PIPER_DRIVER_NAME + ": spike suppresion error\n"); + return ret; + } + piper_reset_mac(piperp); + piper_set_macaddr(piperp); + + return ret; +} + +static void ccw9p9215_piper_set_led(struct piper_priv *piperp, enum wireless_led led, int val) +{ + if(led == STATUS_LED) + leds_event(val ? led_green_on : led_green_off); +} + +static void ccw9p9215_piper_reset(struct piper_priv *piperp, int reset) +{ + gpio_set_value(piperp->pdata->rst_gpio, !reset); +} + +static int ccw9p9215_piper_init(struct piper_priv *piperp) +{ + ccw9p9215_piper_reset(piperp, 1); + mdelay(1); + ccw9p9215_piper_reset(piperp, 0); + mdelay(1); + + /* Initialize functions to access register */ + piperp->ac->wr_reg = write_reg; + piperp->ac->rd_reg = read_reg; + piperp->ac->wr_fifo = write_fifo; + piperp->ac->rd_fifo = read_fifo; + + mdelay(1); + + return piper_init_chip_hw(piperp); +} + +static int ccw9p9215_piper_late_init(struct piper_priv *piperp) +{ + /* Configure irq gpio line */ + gpio_configure_ns921x(piperp->pdata->irq_gpio, NS921X_GPIO_INPUT, + NS921X_GPIO_DONT_INVERT, NS921X_GPIO_FUNC_2, + NS921X_GPIO_ENABLE_PULLUP); + + return 0; +} + +static struct resource piper_resources[] = { + { + .start = 0x70000000, + .end = 0x70000000 + 0x100, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_NS9XXX_EXT0, + .flags = IORESOURCE_IRQ, + } +}; + +/* describes the device */ +static struct platform_device piper_device = { + .id = 0, + .name = PIPER_DRIVER_NAME, + .num_resources = ARRAY_SIZE(piper_resources), + .resource = piper_resources, +}; + +void __init ns9xxx_add_device_ccw9p9215_wifi(struct piper_pdata *pdata) +{ + int ret; + + if (!pdata) + return; + + if (pdata->rst_gpio >= 0) { + ret = gpio_request(pdata->rst_gpio, PIPER_DRIVER_NAME "-reset-gpio"); + if (ret != 0) + printk(KERN_WARNING PIPER_DRIVER_NAME + ": failed to request reset gpio %d\n", pdata->rst_gpio); + else { + /* Configure reset line and hold the chip in reset */ + gpio_direction_output(pdata->rst_gpio, 0); + pdata->reset = ccw9p9215_piper_reset; + } + } + + if (pdata->irq_gpio >= 0) { + ret = gpio_request(pdata->irq_gpio, PIPER_DRIVER_NAME "-irq-gpio"); + if (ret != 0) + printk(KERN_WARNING PIPER_DRIVER_NAME + ": failed to request irq gpio %d\n", pdata->irq_gpio); + } + + /* Configure the memory controller (CS3) with the appropriate settings */ + /* 32 bit bus width */ + writel(MEM_SMC_PB_1 | MEM_SMC_MW_32, MEM_SMC(3)); + /* Static Memory Write Enable Delay x */ + writel(0, MEM_SMWED(3)); + /* Static Memory Output Enable Delay x */ + writel(2, MEM_SMOED(3)); + /* Static Memory Read Delay x */ + writel(8, MEM_SMRD(3)); + /* Static Memory Page Mode Read Delay 0 */ + writel(0, MEM_SMPMRD(3)); + /* Static Memory Write Delay */ + writel(4, MEM_SMWD(3)); + /* Static Memory Turn Round Delay x */ + writel(2, MEM_SWT(3)); + /* Enable the CS0 access */ + writel(readl(SYS_SMCSSMM(3)) | SYS_SMCSSMM_CSEx_EN, SYS_SMCSSMM(3)); + + pdata->rf_transceiver = RF_AIROHA_7230; + pdata->init = ccw9p9215_piper_init; + pdata->late_init = ccw9p9215_piper_late_init; + pdata->set_led = ccw9p9215_piper_set_led; + piper_device.dev.platform_data = pdata; + + platform_device_register(&piper_device); +} + +#else +void __init ns9xxx_add_device_ccw9p9215_wifi(struct piper_pdata *pdata) {} +#endif + diff --git a/arch/arm/mach-ns9xxx/ccw9p9215_devices.h b/arch/arm/mach-ns9xxx/ccw9p9215_devices.h new file mode 100644 index 000000000000..3e27884cd0d8 --- /dev/null +++ b/arch/arm/mach-ns9xxx/ccw9p9215_devices.h @@ -0,0 +1,12 @@ +/* + * arch/arm/mach-ns9xxx/ccw9p9215_devices.h + * + * Copyright (C) 2009 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. + */ + +void __init ns9xxx_add_device_ccw9p9215_wifi(struct piper_pdata *pdata); diff --git a/arch/arm/mach-ns9xxx/ccx9c_devices.c b/arch/arm/mach-ns9xxx/ccx9c_devices.c new file mode 100644 index 000000000000..6ec20a4971f0 --- /dev/null +++ b/arch/arm/mach-ns9xxx/ccx9c_devices.c @@ -0,0 +1,218 @@ +/* + * arch/arm/mach-ns9xxx/ccx9c_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/gpio.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/spi/ads7846.h> + +#include "ns9360_devices.h" +#include "ccx9c_devices.h" + +#if defined(CONFIG_SPI_NS9360) || defined(CONFIG_SPI_NS9360_MODULE) +/* SPI ports and their related GPIOs */ +static struct spi_ns9xxx_data ns9xxx_device_ccx9c_spi_porta_data = { + .gpios = {8, 9, 14, 15}, + .nr_gpios = 4, +}; + +static struct spi_ns9xxx_data ns9xxx_device_ccx9c_spi_portb_data = { + .gpios = {0, 1, 6, 7}, + .nr_gpios = 4, +}; + +static struct spi_ns9xxx_data ns9xxx_device_ccx9c_spi_portc_data = { + .gpios = {40, 41, 22, 23}, + .nr_gpios = 4, +}; + +static struct spi_ns9xxx_data ns9xxx_device_ccx9c_spi_portd_data = { + .gpios = {44, 45, 26, 27}, + .nr_gpios = 4, +}; +#endif + +#if defined(CONFIG_MTD_NAND_CCX9X) || defined(CONFIG_MTD_NAND_CCX9X_MODULE) +static struct ccx9x_nand_info ns9xxx_device_ccx9c_nand_data = { + .addr_offset = 0x8000, + .cmd_offset = 0x10000, + .delay = 25, +}; +void __init ns9xxx_add_device_ccx9c_nand(void) +{ + ns9xxx_add_device_ns9360_nand(&ns9xxx_device_ccx9c_nand_data); +} +#else +void __init ns9xxx_add_device_ccx9c_nand(void) {} +#endif + +#if defined(CONFIG_I2C_NS9XXX) || defined(CONFIG_I2C_NS9XXX_MODULE) +static void ccx9c_i2c_gpio_reconfigure(void) +{ + gpio_configure_ns9360(70, 0, 0, 2); + gpio_configure_ns9360(71, 0, 0, 2); +} + +static struct plat_ns9xxx_i2c ns9xxx_device_ccx9c_i2c_data = { + .gpio_scl = 70, + .gpio_sda = 71, + .speed = 100000, + .gpio_configuration_func = ccx9c_i2c_gpio_reconfigure, +}; + +void __init ns9xxx_add_device_ccx9c_i2c(void) +{ + ns9xxx_add_device_ns9360_i2c(&ns9xxx_device_ccx9c_i2c_data); +} +#else +void __init ns9xxx_add_device_ccx9c_i2c(void) {} +#endif + +#if defined(CONFIG_SERIAL_NS9360) || defined(CONFIG_SERIAL_NS9360_MODULE) +void __init ns9xxx_add_device_ccx9c_uarta_rxtx(void) +{ + int uarta_gpio[] = {8, 9}; + ns9xxx_add_device_ns9360_uarta(uarta_gpio, ARRAY_SIZE(uarta_gpio), 0); +} + +void __init ns9xxx_add_device_ccx9c_uarta_ctsrtsrxtx(void) +{ + int uarta_gpio[] = {8, 9, 10, 11}; + ns9xxx_add_device_ns9360_uarta(uarta_gpio, ARRAY_SIZE(uarta_gpio), 0); +} + +void __init ns9xxx_add_device_ccx9c_uarta_full(void) +{ + int uarta_gpio[] = { 8, 9, 10, 11, 12, 13, 14, 15}; + ns9xxx_add_device_ns9360_uarta(uarta_gpio, ARRAY_SIZE(uarta_gpio), 0); +} + +void __init ns9xxx_add_device_ccx9c_uartb_rxtx(void) +{ + int uartb_gpio[] = {0, 1}; + ns9xxx_add_device_ns9360_uartb(uartb_gpio, ARRAY_SIZE(uartb_gpio), 0); +} + +void __init ns9xxx_add_device_ccx9c_uartb_ctsrtsrxtx(void) +{ + int uartb_gpio[] = {0, 1, 2, 3}; + ns9xxx_add_device_ns9360_uartb(uartb_gpio, ARRAY_SIZE(uartb_gpio), 0); +} + +void __init ns9xxx_add_device_ccx9c_uartb_full(void) +{ + int uartb_gpio[] = { 0, 1, 2, 3, 4, 5, 6, 7}; + ns9xxx_add_device_ns9360_uartb(uartb_gpio, ARRAY_SIZE(uartb_gpio), 0); +} + +void __init ns9xxx_add_device_ccx9c_uartc_rxtx(void) +{ + int uartc_gpio[] = {40, 41}; + ns9xxx_add_device_ns9360_uartc(uartc_gpio, ARRAY_SIZE(uartc_gpio), 0); +} + +void __init ns9xxx_add_device_ccx9c_uartc_ctsrtsrxtx(void) +{ + int uartc_gpio[] = {40, 41, 42, 43}; + ns9xxx_add_device_ns9360_uartc(uartc_gpio, ARRAY_SIZE(uartc_gpio), 0); +} + +void __init ns9xxx_add_device_ccx9c_uartd_rxtx(void) +{ + int uartd_gpio[] = {44, 45}; + ns9xxx_add_device_ns9360_uartd(uartd_gpio, ARRAY_SIZE(uartd_gpio), 0); +} + +void __init ns9xxx_add_device_ccx9c_uartd_ctsrtsrxtx(void) +{ + int uartd_gpio[] = {44, 45, 46, 47}; + ns9xxx_add_device_ns9360_uartd(uartd_gpio, ARRAY_SIZE(uartd_gpio), 0); +} + +void __init ns9xxx_add_device_ccx9c_uartc_full(void) +{ + int uartc_gpio[] = {40, 41, 42, 43, 20, 21, 22, 23}; + ns9xxx_add_device_ns9360_uartc(uartc_gpio, ARRAY_SIZE(uartc_gpio), 0); +} + +void __init ns9xxx_add_device_ccx9c_uartd_full(void) +{ + int uartd_gpio[] = {44, 45, 46, 47, 24, 25, 26, 27}; + ns9xxx_add_device_ns9360_uartd(uartd_gpio, ARRAY_SIZE(uartd_gpio), 0); +} +#else +void __init ns9xxx_add_device_ccx9c_uarta_rxtx(void) {} +void __init ns9xxx_add_device_ccx9c_uarta_ctsrtsrxtx(void) {} +void __init ns9xxx_add_device_ccx9c_uarta_full(void) {} +void __init ns9xxx_add_device_ccx9c_uartb_rxtx(void) {} +void __init ns9xxx_add_device_ccx9c_uartb_ctsrtsrxtx(void) {} +void __init ns9xxx_add_device_ccx9c_uartb_full(void) {} +void __init ns9xxx_add_device_ccx9c_uartc_rxtx(void) {} +void __init ns9xxx_add_device_ccx9c_uartc_ctsrtsrxtx(void) {} +void __init ns9xxx_add_device_ccx9c_uartc_full(void) {} +void __init ns9xxx_add_device_ccx9c_uartd_rxtx(void) {} +void __init ns9xxx_add_device_ccx9c_uartd_ctsrtsrxtx(void) {} +void __init ns9xxx_add_device_ccx9c_uartd_full(void) {} +#endif + +#if defined(CONFIG_FB_NS9360) || defined(CONFIG_FB_NS9360_MODULE) +void __init ns9xxx_add_device_ccx9c_fb(int power) +{ + int gpio[] = {19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41}; + int func[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; + + ns9xxx_add_device_ns9360_fb(gpio, ARRAY_SIZE(gpio), func, power); +} +#else +void __init ns9xxx_add_device_ccx9c_fb(int power) {} +#endif + +#if defined(CONFIG_SPI_NS9360) || defined(CONFIG_SPI_NS9360_MODULE) +void __init ns9xxx_add_device_ccx9c_spi_porta(void) +{ + ns9xxx_add_device_ns9360_spi_porta( &ns9xxx_device_ccx9c_spi_porta_data ); +} + +void __init ns9xxx_add_device_ccx9c_spi_portb(void) +{ + ns9xxx_add_device_ns9360_spi_portb( &ns9xxx_device_ccx9c_spi_portb_data ); +} + +void __init ns9xxx_add_device_ccx9c_spi_portc(void) +{ + ns9xxx_add_device_ns9360_spi_portc( &ns9xxx_device_ccx9c_spi_portc_data ); +} + +void __init ns9xxx_add_device_ccx9c_spi_portd(void) +{ + ns9xxx_add_device_ns9360_spi_portd( &ns9xxx_device_ccx9c_spi_portd_data ); +} + +#else +void __init ns9xxx_add_device_ccx9c_spi_porta(void) {} +void __init ns9xxx_add_device_ccx9c_spi_portb(void) {} +void __init ns9xxx_add_device_ccx9c_spi_portc(void) {} +void __init ns9xxx_add_device_ccx9c_spi_portd(void) {} +#endif + +#if defined(CONFIG_NS9XXX_ETH) || defined(CONFIG_NS9XXX_ETH_MODULE) +void __init ns9xxx_add_device_ccx9c_eth(void) +{ + int gpio[] = {50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64}; + + ns9xxx_add_device_ns9360_eth(gpio, 15, 0, 0xfffffffd); +} +#else +void __init ns9xxx_add_device_ccx9c_eth(void) {} +#endif diff --git a/arch/arm/mach-ns9xxx/ccx9c_devices.h b/arch/arm/mach-ns9xxx/ccx9c_devices.h new file mode 100644 index 000000000000..074197e29aba --- /dev/null +++ b/arch/arm/mach-ns9xxx/ccx9c_devices.h @@ -0,0 +1,32 @@ +/* + * arch/arm/mach-ns9xxx/ccx9c_devices.h + * + * 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. + */ + +void __init ns9xxx_add_device_ccx9c_nand(void); +void __init ns9xxx_add_device_ccx9c_i2c(void); +void __init ns9xxx_add_device_ccx9c_uarta_rxtx(void); +void __init ns9xxx_add_device_ccx9c_uartb_rxtx(void); +void __init ns9xxx_add_device_ccx9c_uartc_rxtx(void); +void __init ns9xxx_add_device_ccx9c_uartd_rxtx(void); +void __init ns9xxx_add_device_ccx9c_uarta_ctsrtsrxtx(void); +void __init ns9xxx_add_device_ccx9c_uartb_ctsrtsrxtx(void); +void __init ns9xxx_add_device_ccx9c_uartc_ctsrtsrxtx(void); +void __init ns9xxx_add_device_ccx9c_uartd_ctsrtsrxtx(void); +void __init ns9xxx_add_device_ccx9c_uarta_full(void); +void __init ns9xxx_add_device_ccx9c_uartb_full(void); +void __init ns9xxx_add_device_ccx9c_uartc_full(void); +void __init ns9xxx_add_device_ccx9c_uartd_full(void); +void __init ns9xxx_add_device_ccx9c_fb(int power); +void __init ns9xxx_add_device_ccx9c_spi_porta(void); +void __init ns9xxx_add_device_ccx9c_spi_portb(void); +void __init ns9xxx_add_device_ccx9c_spi_portc(void); +void __init ns9xxx_add_device_ccx9c_spi_portd(void); +void __init ns9xxx_add_device_ccx9c_eth(void); +void __init ns9xxx_add_device_ccx9c_touch(void); diff --git a/arch/arm/mach-ns9xxx/clock.c b/arch/arm/mach-ns9xxx/clock.c index 44ed20d4a388..0344a519707b 100644 --- a/arch/arm/mach-ns9xxx/clock.c +++ b/arch/arm/mach-ns9xxx/clock.c @@ -1,7 +1,7 @@ /* * arch/arm/mach-ns9xxx/clock.c * - * Copyright (C) 2007 by Digi International Inc. + * Copyright (C) 2007-2008 by Digi International Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify it @@ -61,22 +61,77 @@ EXPORT_SYMBOL(clk_get); void clk_put(struct clk *clk) { + unsigned long flags; + + spin_lock_irqsave(&clk_lock, flags); + module_put(clk->owner); --clk->refcount; + + spin_unlock_irqrestore(&clk_lock, flags); } EXPORT_SYMBOL(clk_put); -static int clk_enable_unlocked(struct clk *clk) +static int clk_enable_haslock(struct clk *clk); +static int clk_disable_haslock(struct clk *clk); + +static void clk_disable_parent_haslock(struct clk *clk) { + struct clk *parent = clk->parent; int ret = 0; - if (clk->parent) { - ret = clk_enable_unlocked(clk->parent); - if (ret) - return ret; + + if (parent) + ret = clk_disable_haslock(parent); + + if (unlikely(ret)) + pr_warning("failed to disable %s.%d clk -> %d\n", + parent->name, parent->id, ret); +} + +static int clk_enable_haslocknchange(struct clk *clk) +{ + int ret = 0; + + assert_spin_locked(&clk_lock); + BUG_ON(!test_bit(CLK_FLAG_CHANGESTATE, &clk->flags)); + + if (clk->usage++ == 0) { + if (clk->parent) { + ret = clk_enable_haslock(clk->parent); + if (ret) + goto err_enable_parent; + } + + spin_unlock(&clk_lock); + + if (clk->endisable) + ret = clk->endisable(clk, 1); + + spin_lock(&clk_lock); + + if (ret) { + clk_disable_parent_haslock(clk); +err_enable_parent: + + clk->usage = 0; + } + } - if (clk->usage++ == 0 && clk->endisable) - ret = clk->endisable(clk, 1); + return ret; +} + +static int clk_enable_haslock(struct clk *clk) +{ + int ret; + + assert_spin_locked(&clk_lock); + if (__test_and_set_bit(CLK_FLAG_CHANGESTATE, &clk->flags)) + return -EBUSY; + + ret = clk_enable_haslocknchange(clk); + + clear_bit(CLK_FLAG_CHANGESTATE, &clk->flags); return ret; } @@ -88,7 +143,7 @@ int clk_enable(struct clk *clk) spin_lock_irqsave(&clk_lock, flags); - ret = clk_enable_unlocked(clk); + ret = clk_enable_haslock(clk); spin_unlock_irqrestore(&clk_lock, flags); @@ -96,24 +151,60 @@ int clk_enable(struct clk *clk) } EXPORT_SYMBOL(clk_enable); -static void clk_disable_unlocked(struct clk *clk) +static int clk_disable_haslocknchange(struct clk *clk) { - if (--clk->usage == 0 && clk->endisable) - clk->endisable(clk, 0); + int ret = 0; - if (clk->parent) - clk_disable_unlocked(clk->parent); + assert_spin_locked(&clk_lock); + BUG_ON(!test_bit(CLK_FLAG_CHANGESTATE, &clk->flags)); + + BUG_ON(clk->usage == 0); + + if (--clk->usage == 0) { + spin_unlock(&clk_lock); + + if (clk->endisable) + ret = clk->endisable(clk, 0); + + spin_lock(&clk_lock); + + if (ret == 0) + clk_disable_parent_haslock(clk); + else + clk->usage = 1; + } + + return ret; +} + +static int clk_disable_haslock(struct clk *clk) +{ + int ret; + + if (__test_and_set_bit(CLK_FLAG_CHANGESTATE, &clk->flags)) + return -EBUSY; + + ret = clk_disable_haslocknchange(clk); + + clear_bit(CLK_FLAG_CHANGESTATE, &clk->flags); + + return ret; } void clk_disable(struct clk *clk) { + int ret; unsigned long flags; spin_lock_irqsave(&clk_lock, flags); - clk_disable_unlocked(clk); + ret = clk_disable_haslock(clk); spin_unlock_irqrestore(&clk_lock, flags); + + if (unlikely(ret)) + pr_warning("failed to disable %s.%d clk -> %d\n", + clk->name, clk->id, ret); } EXPORT_SYMBOL(clk_disable); @@ -138,6 +229,8 @@ int clk_register(struct clk *clk) spin_lock_irqsave(&clk_lock, flags); + BUG_ON(clk->flags); + list_add(&clk->node, &clocks); if (clk->parent) @@ -181,9 +274,10 @@ static int clk_debugfs_show(struct seq_file *s, void *null) spin_lock_irqsave(&clk_lock, flags); list_for_each_entry(p, &clocks, node) - seq_printf(s, "%s.%d: usage=%lu refcount=%lu rate=%lu\n", + seq_printf(s, "%s.%d: usage=%lu refcount=%lu rate=%lu parent=%s\n", p->name, p->id, p->usage, p->refcount, - p->usage ? clk_get_rate(p) : 0); + p->usage ? clk_get_rate(p) : 0, + p->parent ? p->parent->name : "<nil>"); spin_unlock_irqrestore(&clk_lock, flags); diff --git a/arch/arm/mach-ns9xxx/clock.h b/arch/arm/mach-ns9xxx/clock.h index b86c30dd79eb..9097fe971dfc 100644 --- a/arch/arm/mach-ns9xxx/clock.h +++ b/arch/arm/mach-ns9xxx/clock.h @@ -27,6 +27,9 @@ struct clk { struct list_head node; unsigned long refcount; unsigned long usage; + +#define CLK_FLAG_CHANGESTATE 0 + unsigned long flags; }; int clk_register(struct clk *clk); diff --git a/arch/arm/mach-ns9xxx/cme9210_devices.c b/arch/arm/mach-ns9xxx/cme9210_devices.c new file mode 100644 index 000000000000..c3b3ff05b999 --- /dev/null +++ b/arch/arm/mach-ns9xxx/cme9210_devices.c @@ -0,0 +1,251 @@ + /* + * arch/arm/mach-ns9xxx/cme9210_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/mtd/physmap.h> +#include <mach/fim-ns921x.h> +#include <linux/gpio.h> +#include <linux/mmc/host.h> +#include <linux/w1-gpio.h> + +#include "ns921x_devices.h" +#include "cme9210_devices.h" + +#if defined(CONFIG_NS9XXX_ETH) || defined(CONFIG_NS9XXX_ETH_MODULE) +void __init ns9xxx_add_device_cme9210_eth(void) +{ + int gpio[] = { +#ifdef CONFIG_GPIO_ETH_ACTIVITY_LED + 14, +#endif + 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49}; + int func[] = { +#ifdef CONFIG_GPIO_ETH_ACTIVITY_LED + 3, +#endif + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0}; + int dir[] = { +#ifdef CONFIG_GPIO_ETH_ACTIVITY_LED + 1, +#endif + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + ns9xxx_add_device_ns921x_eth(NULL, 0, gpio, + func, dir, ARRAY_SIZE(gpio)); +} +#else +void __init ns9xxx_add_device_cme9210_eth(void) {} +#endif + +#if defined(CONFIG_I2C_NS9XXX) || defined(CONFIG_I2C_NS9XXX_MODULE) +static void cme9210_i2c_gpio_reconfigure(void) +{ + gpio_configure_ns921x(9, 0, 0, 1, 0); + gpio_configure_ns921x(12, 0, 0, 1, 0); +} + +static struct plat_ns9xxx_i2c ns9xxx_device_cme9210_i2c_data = { + .gpio_scl = 9, + .gpio_sda = 12, + .speed = 100000, + .gpio_configuration_func = cme9210_i2c_gpio_reconfigure, +}; + +void __init ns9xxx_add_device_cme9210_i2c(void) +{ + ns9xxx_add_device_ns921x_i2c(&ns9xxx_device_cme9210_i2c_data); +} +#else +void __init ns9xxx_add_device_cme9210_i2c(void) {} +#endif + +#if defined(CONFIG_SERIAL_NS921X) || defined(CONFIG_SERIAL_NS921X_MODULE) +void __init ns9xxx_add_device_cme9210_uarta(int gpio_nr) +{ + ns9xxx_add_device_ns921x_uarta(0, gpio_nr, 0); +} +void __init ns9xxx_add_device_cme9210_uartc(int gpio_nr) +{ + ns9xxx_add_device_ns921x_uartc(8, gpio_nr, 0); +} +#else +void __init ns9xxx_add_device_cme9210_uarta(int gpio_nr) {} +void __init ns9xxx_add_device_cme9210_uartc(int gpio_nr) {} +#endif + +#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP) +static struct physmap_flash_data ns9xxx_device_cme9210_flash_data = { + .width = 2, +}; + +void __init ns9xxx_add_device_cme9210_flash(void) +{ + ns9xxx_add_device_ns921x_flash(&ns9xxx_device_cme9210_flash_data); +} +#else +void __init ns9xxx_add_device_cme9210_flash(void) {} +#endif + +#if defined(CONFIG_SPI_NS921X) || defined(CONFIG_SPI_NS921X_MODULE) +/* SPI ports and their related GPIOs */ +static struct spi_ns9xxx_data ns9xxx_device_cme9210_spi_data = { + .gpios = {7, 3, 5, 0}, + .gpio_funcs = { NS921X_GPIO_FUNC_4, + NS921X_GPIO_FUNC_4, + NS921X_GPIO_FUNC_4, + NS921X_GPIO_FUNC_4 }, + .nr_gpios = 4, +}; + +void __init ns9xxx_add_device_cme9210_spi(void) +{ + ns9xxx_add_device_ns921x_spi(&ns9xxx_device_cme9210_spi_data); +} +#else +void __init ns9xxx_add_device_cme9210_spi(void) {} +#endif + +/* + * XXX Need testing and it might be incomplete add_device()? + */ + +#if defined(CONFIG_FIM_ZERO_SERIAL) +static struct fim_serial_platform_data fim_serial_data0 = { + .fim_nr = 0, +#if defined(CONFIG_FIM_ZERO_SERIAL_CTSRTS) + NS921X_FIM_SERIAL_GPIOS(2, 1, /* RX(2,23) + TX(1) */ + 0, 3, /* RTS(0) + CTS(3) */ + NS921X_GPIO_FUNC_2), +#else + NS921X_FIM_SERIAL_GPIOS(2, 1, /* RX(2,23) + TX(1) */ + FIM_GPIO_DONT_USE, /* RTS */ + FIM_GPIO_DONT_USE, /* CTS */ + NS921X_GPIO_FUNC_2), +#endif +}; +struct platform_device ns921x_fim_serial0 = { + .name = "fim-serial", + .id = 0, + .dev.platform_data = &fim_serial_data0, +}; +EXPORT_SYMBOL(ns921x_fim_serial0); +#endif /* CONFIG_FIM_ZERO_SERIAL */ + +#if defined(CONFIG_FIM_ONE_CAN) +static struct fim_can_platform_data fim_can_data1 = { + .fim_nr = 1, + .fim_can_bitrate = 500000, + NS921X_FIM_CAN_GPIOS( 23, 24, /* RX(2,23) + TX(6,24) */ + NS921X_GPIO_FUNC_2), +}; +struct platform_device ns921x_fim_can1 = { + .name = "fim-can", + .id = 1, + .dev.platform_data = &fim_can_data1, +}; +EXPORT_SYMBOL(ns921x_fim_can1); +#endif /* CONFIG_FIM_ONE_CAN */ + +#if defined(CONFIG_FIM_ZERO_SDIO) +static struct fim_sdio_platform_data fim_sdio_data0 = { + .fim_nr = 0, + .host_caps = 0, + + .d0_gpio_nr = 0, + .d0_gpio_func = NS921X_GPIO_FUNC_2, + .d1_gpio_nr = FIM_GPIO_DONT_USE, + .d2_gpio_nr = FIM_GPIO_DONT_USE, + .d3_gpio_nr = FIM_GPIO_DONT_USE, + + .clk_gpio_nr = 1, + .clk_gpio_func = NS921X_GPIO_FUNC_2, + + .cmd_gpio_nr = 2, + .cmd_gpio_func = NS921X_GPIO_FUNC_2, + + .cd_gpio_nr = 9, + .cd_gpio_func = NS921X_GPIO_FUNC_2, + + .wp_gpio_nr = 6, + .wp_gpio_func = NS921X_GPIO_FUNC_3, +}; +struct platform_device ns921x_fim_sdio0 = { + .name = "fim-sdio", + .id = 0, + .dev.platform_data = &fim_sdio_data0, +}; +EXPORT_SYMBOL(ns921x_fim_sdio0); +#endif /* CONFIG_FIM_ZERO_SDIO */ + +/* The second SDIO-port will be available by the CC9P9210JS first */ +#if defined(CONFIG_FIM_ONE_SDIO) +static struct fim_sdio_platform_data fim_sdio_data1 = { + .fim_nr = 1, + .host_caps = 0, + + .d0_gpio_nr = 26, + .d0_gpio_func = NS921X_GPIO_FUNC_2, + .d1_gpio_nr = FIM_GPIO_DONT_USE, + .d2_gpio_nr = FIM_GPIO_DONT_USE, + .d3_gpio_nr = FIM_GPIO_DONT_USE, + + .clk_gpio_nr = 27, + .clk_gpio_func = NS921X_GPIO_FUNC_2, + + .cmd_gpio_nr = 28, + .cmd_gpio_func = NS921X_GPIO_FUNC_2, + + .cd_gpio_nr = 9, + .cd_gpio_func = NS921X_GPIO_FUNC_2, + + .wp_gpio_nr = 6, + .wp_gpio_func = NS921X_GPIO_FUNC_3, +}; +struct platform_device ns921x_fim_sdio1 = { + .name = "fim-sdio", + .id = 1, + .dev.platform_data = &fim_sdio_data1, +}; +EXPORT_SYMBOL(ns921x_fim_sdio1); +#endif /* CONFIG_FIM_ONE_SDIO */ + +#if defined(CONFIG_FIM_ZERO_W1) +static struct w1_gpio_platform_data fim_w1_data0 = { + .pin = 1, + .is_open_drain = 0, +}; +struct platform_device ns921x_fim0_w1 = { + .name = "w1-gpio", + .id = 0, + .dev = { + .platform_data = &fim_w1_data0, + }, +}; +EXPORT_SYMBOL(ns921x_fim0_w1); +#endif /* CONFIG_FIM_ZERO_W1 */ + +#if defined(CONFIG_FIM_ZERO_USB) +static struct fim_usb_platform_data fim_usb_data0 = { + .fim_nr = 0, + NS921X_FIM_USB_GPIOS(0, 1, 2, /* VP + VM + RCV */ + 3, 6, 9, /* OE_L + ENUM + SPND */ + NS921X_GPIO_FUNC_2, + NS921X_GPIO_FUNC_GPIO), +}; +struct platform_device ns921x_fim_usb0 = { + .name = "fim-usb", + .id = 0, + .dev.platform_data = &fim_usb_data0, +}; +EXPORT_SYMBOL(ns921x_fim_usb0); +#endif /* CONFIG_FIM_ZERO_USB */ diff --git a/arch/arm/mach-ns9xxx/cme9210_devices.h b/arch/arm/mach-ns9xxx/cme9210_devices.h new file mode 100644 index 000000000000..606ed71a244f --- /dev/null +++ b/arch/arm/mach-ns9xxx/cme9210_devices.h @@ -0,0 +1,26 @@ +/* + * arch/arm/mach-ns9xxx/cme9210_devices.h + * + * 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. + */ + +void __init ns9xxx_add_device_cme9210_eth(void); +void __init ns9xxx_add_device_cme9210_uarta(int gpio_nr); +void __init ns9xxx_add_device_cme9210_uartc(int gpio_nr); +void __init ns9xxx_add_device_cme9210_flash(void); +void __init ns9xxx_add_device_cme9210_spi(void); +void __init ns9xxx_add_device_cme9210_i2c(void); + +#define ns9xxx_add_device_cme9210_uarta_rxtx() \ + ns9xxx_add_device_cme9210_uarta(2) +#define ns9xxx_add_device_cme9210_uarta_ctsrtsrxtx() \ + ns9xxx_add_device_cme9210_uarta(4) +#define ns9xxx_add_device_cme9210_uarta_full() \ + ns9xxx_add_device_cme9210_uarta(8) +#define ns9xxx_add_device_cme9210_uartc_rxtx() \ + ns9xxx_add_device_cme9210_uartc(2) diff --git a/arch/arm/mach-ns9xxx/gpio-ns921x.c b/arch/arm/mach-ns9xxx/gpio-ns921x.c new file mode 100644 index 000000000000..fff11e82c862 --- /dev/null +++ b/arch/arm/mach-ns9xxx/gpio-ns921x.c @@ -0,0 +1,41 @@ +/* + * arch/arm/mach-ns9xxx/gpio-ns921x.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/module.h> + +#include <asm/gpio.h> +#include <mach/irqs.h> + +static const struct gpio_to_irq_map gpio_to_irq_map_ns921x[] = { + { .gpio = 1, .irq = IRQ_NS9XXX_EXT0, .func = 1, }, + { .gpio = 2, .irq = IRQ_NS9XXX_EXT1, .func = 1, }, + { .gpio = 4, .irq = IRQ_NS9XXX_EXT2, .func = 1, }, + { .gpio = 5, .irq = IRQ_NS9XXX_EXT3, .func = 1, }, + { .gpio = 9, .irq = IRQ_NS9XXX_EXT0, .func = 2, }, + { .gpio = 10, .irq = IRQ_NS9XXX_EXT1, .func = 2, }, + { .gpio = 16, .irq = IRQ_NS9XXX_EXT0, .func = 2, }, + { .gpio = 17, .irq = IRQ_NS9XXX_EXT1, .func = 2, }, + { .gpio = 18, .irq = IRQ_NS9XXX_EXT2, .func = 2, }, + { .gpio = 19, .irq = IRQ_NS9XXX_EXT3, .func = 2, }, +#if defined(CONFIG_PROCESSOR_NS9215) + { .gpio = 67, .irq = IRQ_NS9XXX_EXT3, .func = 2, }, + { .gpio = 101, .irq = IRQ_NS9XXX_EXT3, .func = 2, }, +#endif + { .gpio = 104, .irq = IRQ_NS9XXX_EXT0, .func = 2, }, + { .gpio = 105, .irq = IRQ_NS9XXX_EXT1, .func = 2, }, + { .gpio = 106, .irq = IRQ_NS9XXX_EXT2, .func = 2, }, +}; + +const struct gpio_to_irq_map *gpio_get_map_ns921x(unsigned gpio) +{ + return gpio_get_map(gpio, gpio_to_irq_map_ns921x, + ARRAY_SIZE(gpio_to_irq_map_ns921x)); +} +EXPORT_SYMBOL(gpio_get_map_ns921x); diff --git a/arch/arm/mach-ns9xxx/gpio-ns9360.c b/arch/arm/mach-ns9xxx/gpio-ns9360.c index 377330c1b250..6bc3e74207d9 100644 --- a/arch/arm/mach-ns9xxx/gpio-ns9360.c +++ b/arch/arm/mach-ns9xxx/gpio-ns9360.c @@ -1,118 +1,34 @@ /* * arch/arm/mach-ns9xxx/gpio-ns9360.c * - * Copyright (C) 2006,2007 by Digi International Inc. + * 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/bug.h> -#include <linux/errno.h> -#include <linux/io.h> -#include <linux/kernel.h> #include <linux/module.h> -#include <mach/regs-bbu.h> -#include <mach/processor-ns9360.h> +#include <asm/gpio.h> +#include <mach/irqs.h> -#include "gpio-ns9360.h" +static const struct gpio_to_irq_map gpio_to_irq_map_ns9360[] = { + { .gpio = 1, .irq = IRQ_NS9XXX_EXT0, .func = 2, }, + { .gpio = 7, .irq = IRQ_NS9XXX_EXT1, .func = 2, }, + { .gpio = 11, .irq = IRQ_NS9XXX_EXT2, .func = 1, }, + { .gpio = 13, .irq = IRQ_NS9XXX_EXT0, .func = 1, }, + { .gpio = 18, .irq = IRQ_NS9XXX_EXT3, .func = 2, }, + { .gpio = 28, .irq = IRQ_NS9XXX_EXT1, .func = 0, }, + { .gpio = 32, .irq = IRQ_NS9XXX_EXT2, .func = 0, }, + { .gpio = 40, .irq = IRQ_NS9XXX_EXT3, .func = 1, }, + { .gpio = 68, .irq = IRQ_NS9XXX_EXT0, .func = 2, }, + { .gpio = 69, .irq = IRQ_NS9XXX_EXT1, .func = 2, }, +}; -static inline int ns9360_valid_gpio(unsigned gpio) +const struct gpio_to_irq_map *gpio_get_map_ns9360(unsigned gpio) { - return gpio <= 72; -} - -static inline void __iomem *ns9360_gpio_get_gconfaddr(unsigned gpio) -{ - if (gpio < 56) - return BBU_GCONFb1(gpio / 8); - else - /* - * this could be optimised away on - * ns9750 only builds, but it isn't ... - */ - return BBU_GCONFb2((gpio - 56) / 8); -} - -static inline void __iomem *ns9360_gpio_get_gctrladdr(unsigned gpio) -{ - if (gpio < 32) - return BBU_GCTRL1; - else if (gpio < 64) - return BBU_GCTRL2; - else - /* this could be optimised away on ns9750 only builds */ - return BBU_GCTRL3; -} - -static inline void __iomem *ns9360_gpio_get_gstataddr(unsigned gpio) -{ - if (gpio < 32) - return BBU_GSTAT1; - else if (gpio < 64) - return BBU_GSTAT2; - else - /* this could be optimised away on ns9750 only builds */ - return BBU_GSTAT3; -} - -/* - * each gpio can serve for 4 different purposes [0..3]. These are called - * "functions" and passed in the parameter func. Functions 0-2 are always some - * special things, function 3 is GPIO. If func == 3 dir specifies input or - * output, and with inv you can enable an inverter (independent of func). - */ -int __ns9360_gpio_configure(unsigned gpio, int dir, int inv, int func) -{ - void __iomem *conf = ns9360_gpio_get_gconfaddr(gpio); - u32 confval; - - confval = __raw_readl(conf); - REGSETIM_IDX(confval, BBU_GCONFx, DIR, gpio & 7, dir); - REGSETIM_IDX(confval, BBU_GCONFx, INV, gpio & 7, inv); - REGSETIM_IDX(confval, BBU_GCONFx, FUNC, gpio & 7, func); - __raw_writel(confval, conf); - - return 0; -} - -int ns9360_gpio_configure(unsigned gpio, int inv, int func) -{ - if (likely(ns9360_valid_gpio(gpio))) { - if (func == 3) { - printk(KERN_WARNING "use gpio_direction_input " - "or gpio_direction_output\n"); - return -EINVAL; - } else - return __ns9360_gpio_configure(gpio, 0, inv, func); - } else - return -EINVAL; -} -EXPORT_SYMBOL(ns9360_gpio_configure); - -int ns9360_gpio_get_value(unsigned gpio) -{ - void __iomem *stat = ns9360_gpio_get_gstataddr(gpio); - int ret; - - ret = 1 & (__raw_readl(stat) >> (gpio & 31)); - - return ret; -} - -void ns9360_gpio_set_value(unsigned gpio, int value) -{ - void __iomem *ctrl = ns9360_gpio_get_gctrladdr(gpio); - u32 ctrlval; - - ctrlval = __raw_readl(ctrl); - - if (value) - ctrlval |= 1 << (gpio & 31); - else - ctrlval &= ~(1 << (gpio & 31)); - - __raw_writel(ctrlval, ctrl); + return gpio_get_map(gpio, gpio_to_irq_map_ns9360, + ARRAY_SIZE(gpio_to_irq_map_ns9360)); } +EXPORT_SYMBOL(gpio_get_map_ns9360); diff --git a/arch/arm/mach-ns9xxx/gpio.c b/arch/arm/mach-ns9xxx/gpio.c index 5503ca09c4ae..374e312bd7dd 100644 --- a/arch/arm/mach-ns9xxx/gpio.c +++ b/arch/arm/mach-ns9xxx/gpio.c @@ -1,61 +1,33 @@ /* * arch/arm/mach-ns9xxx/gpio.c * - * Copyright (C) 2006,2007 by Digi International Inc. + * Copyright (C) 2006-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/kernel.h> #include <linux/compiler.h> #include <linux/init.h> #include <linux/spinlock.h> #include <linux/module.h> -#include <linux/bitops.h> -#include <mach/gpio.h> -#include <mach/processor.h> -#include <mach/processor-ns9360.h> #include <asm/bug.h> #include <asm/types.h> +#include <asm/bitops.h> -#include "gpio-ns9360.h" - -#if defined(CONFIG_PROCESSOR_NS9360) -#define GPIO_MAX 72 -#elif defined(CONFIG_PROCESSOR_NS9750) -#define GPIO_MAX 49 -#endif +#include <mach/gpio.h> +#include <mach/processor.h> -/* protects BBU_GCONFx and BBU_GCTRLx */ -static spinlock_t gpio_lock = __SPIN_LOCK_UNLOCKED(gpio_lock); +DEFINE_SPINLOCK(gpio_lock); /* only access gpiores with atomic ops */ -static DECLARE_BITMAP(gpiores, GPIO_MAX + 1); - -static inline int ns9xxx_valid_gpio(unsigned gpio) -{ -#if defined(CONFIG_PROCESSOR_NS9360) - if (processor_is_ns9360()) - return gpio <= 72; - else -#endif -#if defined(CONFIG_PROCESSOR_NS9750) - if (processor_is_ns9750()) - return gpio <= 49; - else -#endif - { - BUG(); - return 0; - } -} +static DECLARE_BITMAP(gpiores, NS9XXX_NUM_GPIO); int gpio_request(unsigned gpio, const char *label) { - if (likely(ns9xxx_valid_gpio(gpio))) + if (likely(gpio_issocgpio(gpio))) return test_and_set_bit(gpio, gpiores) ? -EBUSY : 0; else return -EINVAL; @@ -64,84 +36,7 @@ EXPORT_SYMBOL(gpio_request); void gpio_free(unsigned gpio) { - might_sleep(); clear_bit(gpio, gpiores); return; } EXPORT_SYMBOL(gpio_free); - -int gpio_direction_input(unsigned gpio) -{ - if (likely(ns9xxx_valid_gpio(gpio))) { - int ret = -EINVAL; - unsigned long flags; - - spin_lock_irqsave(&gpio_lock, flags); -#if defined(CONFIG_PROCESSOR_NS9360) - if (processor_is_ns9360()) - ret = __ns9360_gpio_configure(gpio, 0, 0, 3); - else -#endif - BUG(); - - spin_unlock_irqrestore(&gpio_lock, flags); - - return ret; - - } else - return -EINVAL; -} -EXPORT_SYMBOL(gpio_direction_input); - -int gpio_direction_output(unsigned gpio, int value) -{ - if (likely(ns9xxx_valid_gpio(gpio))) { - int ret = -EINVAL; - unsigned long flags; - - gpio_set_value(gpio, value); - - spin_lock_irqsave(&gpio_lock, flags); -#if defined(CONFIG_PROCESSOR_NS9360) - if (processor_is_ns9360()) - ret = __ns9360_gpio_configure(gpio, 1, 0, 3); - else -#endif - BUG(); - - spin_unlock_irqrestore(&gpio_lock, flags); - - return ret; - } else - return -EINVAL; -} -EXPORT_SYMBOL(gpio_direction_output); - -int gpio_get_value(unsigned gpio) -{ -#if defined(CONFIG_PROCESSOR_NS9360) - if (processor_is_ns9360()) - return ns9360_gpio_get_value(gpio); - else -#endif - { - BUG(); - return -EINVAL; - } -} -EXPORT_SYMBOL(gpio_get_value); - -void gpio_set_value(unsigned gpio, int value) -{ - unsigned long flags; - spin_lock_irqsave(&gpio_lock, flags); -#if defined(CONFIG_PROCESSOR_NS9360) - if (processor_is_ns9360()) - ns9360_gpio_set_value(gpio, value); - else -#endif - BUG(); - - spin_unlock_irqrestore(&gpio_lock, flags); -} -EXPORT_SYMBOL(gpio_set_value); diff --git a/arch/arm/mach-ns9xxx/gpiolib-ns921x.c b/arch/arm/mach-ns9xxx/gpiolib-ns921x.c new file mode 100644 index 000000000000..e8a513171d26 --- /dev/null +++ b/arch/arm/mach-ns9xxx/gpiolib-ns921x.c @@ -0,0 +1,76 @@ +/* + * arch/arm/mach-ns9xxx/gpiolib-ns921x.c + * + * Copyright (C) 2007-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/init.h> +#include <linux/errno.h> + +#include <asm/gpio.h> + +#include <mach/processor.h> + +static int ns921x_gpio_chip_get(struct gpio_chip *chip, unsigned offset) +{ + return gpio_get_value_ns921x(chip->base + offset); +} + +static void ns921x_gpio_chip_set(struct gpio_chip *chip, + unsigned offset, int value) +{ + gpio_set_value_ns921x_unlocked(chip->base + offset, value); +} + +static int ns921x_gpio_chip_dir_input(struct gpio_chip *chip, unsigned offset) +{ + return gpio_direction_irqinput_ns921x_unlocked(chip->base + offset); +} + +static int ns921x_gpio_chip_dir_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + return gpio_direction_output_ns921x_unlocked(chip->base + offset, + value); +} + +static struct gpio_chip ns921x_gpio_chip = { + .label = "ns921x-system-gpio", + .direction_input = ns921x_gpio_chip_dir_input, + .direction_output = ns921x_gpio_chip_dir_output, + .get = ns921x_gpio_chip_get, + .set = ns921x_gpio_chip_set, + .base = 0, +}; + +static struct gpio_chip ns921x_gpio_a_chip = { + .label = "ns921x-system-gpio", + .direction_input = ns921x_gpio_chip_dir_input, + .direction_output = ns921x_gpio_chip_dir_output, + .get = ns921x_gpio_chip_get, + .set = ns921x_gpio_chip_set, + .base = 104, + .ngpio = 4, +}; + +int __init ns921x_gpio_init(void) +{ + int ret; + + if (processor_is_ns9210()) + ns921x_gpio_chip.ngpio = 50; + else if (processor_is_ns9215()) + ns921x_gpio_chip.ngpio = 104; + else + return -EINVAL; + + ret = gpiochip_add(&ns921x_gpio_chip); + if (ret) + return ret; + + return gpiochip_add(&ns921x_gpio_a_chip); +} diff --git a/arch/arm/mach-ns9xxx/gpiolib-ns921x.h b/arch/arm/mach-ns9xxx/gpiolib-ns921x.h new file mode 100644 index 000000000000..73b3a754b411 --- /dev/null +++ b/arch/arm/mach-ns9xxx/gpiolib-ns921x.h @@ -0,0 +1,12 @@ +/* + * arch/arm/mach-ns9xxx/gpiolib-ns921x.h + * + * Copyright (C) 2006-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. + */ + +int __init ns921x_gpio_init(void); diff --git a/arch/arm/mach-ns9xxx/gpiolib-ns9360.c b/arch/arm/mach-ns9xxx/gpiolib-ns9360.c new file mode 100644 index 000000000000..310dde70fea6 --- /dev/null +++ b/arch/arm/mach-ns9xxx/gpiolib-ns9360.c @@ -0,0 +1,59 @@ +/* + * arch/arm/mach-ns9xxx/gpiolib-ns9360.c + * + * Copyright (C) 2006-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/bug.h> +#include <linux/errno.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> + +#include <asm/gpio.h> + +static int ns9360_gpio_chip_get(struct gpio_chip *chip, unsigned offset) +{ + return gpio_get_value_ns9360(chip->base + offset); +} + +static void ns9360_gpio_chip_set(struct gpio_chip *chip, + unsigned offset, int value) +{ + gpio_set_value_ns9360_unlocked(chip->base + offset, value); +} + +static int ns9360_gpio_chip_dir_input(struct gpio_chip *chip, unsigned offset) +{ + return gpio_direction_irqinput_ns9360_unlocked(chip->base + offset); +} + +static int ns9360_gpio_chip_dir_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + return gpio_direction_output_ns9360_unlocked(chip->base + offset, + value); +} + +static struct gpio_chip ns9360_gpio_chip = { + .label = "ns9360-system-gpio", + .direction_input = ns9360_gpio_chip_dir_input, + .direction_output = ns9360_gpio_chip_dir_output, + .get = ns9360_gpio_chip_get, + .set = ns9360_gpio_chip_set, + .base = 0, + .ngpio = 72, +}; + +int __init ns9360_gpio_init(void) +{ + if (!processor_is_ns9360()) + return -EINVAL; + + return gpiochip_add(&ns9360_gpio_chip); +} + diff --git a/arch/arm/mach-ns9xxx/gpiolib-ns9360.h b/arch/arm/mach-ns9xxx/gpiolib-ns9360.h new file mode 100644 index 000000000000..ea37e0b4dd8c --- /dev/null +++ b/arch/arm/mach-ns9xxx/gpiolib-ns9360.h @@ -0,0 +1,12 @@ +/* + * arch/arm/mach-ns9xxx/gpiolib-ns9360.h + * + * Copyright (C) 2006-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. + */ + +int __init ns9360_gpio_init(void); diff --git a/arch/arm/mach-ns9xxx/include/mach/board.h b/arch/arm/mach-ns9xxx/include/mach/board.h index f7e9196eb9ab..247c0034e573 100644 --- a/arch/arm/mach-ns9xxx/include/mach/board.h +++ b/arch/arm/mach-ns9xxx/include/mach/board.h @@ -31,10 +31,18 @@ || machine_is_cc9p9215js() \ ) +#define board_is_jsccw9p9215() (0 \ + || machine_is_ccw9p9215js() \ + ) + #define board_is_jscc9p9360() (0 \ || machine_is_cc9p9360js() \ ) +#define board_is_jscme9210() (0 \ + || machine_is_cme9210js() \ + ) + #define board_is_uncbas() (0 \ || machine_is_cc7ucamry() \ ) diff --git a/arch/arm/mach-ns9xxx/include/mach/display/CUSTOM.h b/arch/arm/mach-ns9xxx/include/mach/display/CUSTOM.h new file mode 100644 index 000000000000..2eceb4b94494 --- /dev/null +++ b/arch/arm/mach-ns9xxx/include/mach/display/CUSTOM.h @@ -0,0 +1,18 @@ + + + +/* +#define CUSTOM_DISPLAY \ +{ \ + .display_name = "CUSTOM", \ + .width = , \ + .height = , \ + .control = NS9360_DISPLAY_CONTROL, \ + .timing = { \ + NS9360_DISPLAY_TIMING0, \ + NS9360_DISPLAY_TIMING1, \ + NS9360_DISPLAY_TIMING2, \ + }, \ + .clock = NS9360_DISPLAY_CLOCK, \ +} +*/
\ No newline at end of file diff --git a/arch/arm/mach-ns9xxx/include/mach/display/Kconfig b/arch/arm/mach-ns9xxx/include/mach/display/Kconfig new file mode 100644 index 000000000000..842eb775185e --- /dev/null +++ b/arch/arm/mach-ns9xxx/include/mach/display/Kconfig @@ -0,0 +1,36 @@ +# arch/arm/mach-ns9xxx/displays/Kconfig +# +# Copyright 2009 Digi International Inc +# + +if (CC9P9360JS_FB || CCX9C_FB) + +comment "Display selection" + +config NS9XXX_FB_VGA + bool "CRT VGA video support" + depends on ! (CC9P9360JS_SERIAL_PORTA_FULL || CCX9C_SERIAL_PORTA_FULL || CCW9C_SERIAL_PORTA_FULL) + def_bool y + help + This enables the video support for the VGA intrface. + +config NS9XXX_FB_LQ057Q3DC12I + bool "LQ057Q3DC12I TFT LCD support" + depends on ! (CC9P9360JS_SERIAL_PORTA_FULL || CCX9C_SERIAL_PORTA_FULL || CCW9C_SERIAL_PORTA_FULL) + help + This enables the support for the LQ057Q3DC12I TFT display. + +config NS9XXX_FB_LQ064V3DG01 + bool "LQ064V3DG01 TFT LCD support" + depends on ! (CC9P9360JS_SERIAL_PORTA_FULL || CCX9C_SERIAL_PORTA_FULL || CCW9C_SERIAL_PORTA_FULL) + help + This enables the support for the LQ064V3DG01 TFT display. + +config NS9XXX_FB_CUSTOM + bool "Custom display support" + depends on ! (CC9P9360JS_SERIAL_PORTA_FULL || CCX9C_SERIAL_PORTA_FULL || CCW9C_SERIAL_PORTA_FULL) + help + This enables the support for a customer specific display. + displays/CUSTOM.h has to be modified when selecting this. + +endif diff --git a/arch/arm/mach-ns9xxx/include/mach/display/LQ057Q3DC12I.h b/arch/arm/mach-ns9xxx/include/mach/display/LQ057Q3DC12I.h new file mode 100644 index 000000000000..afaf151cab2b --- /dev/null +++ b/arch/arm/mach-ns9xxx/include/mach/display/LQ057Q3DC12I.h @@ -0,0 +1,27 @@ + +#define LQ057Q3DC12I_DISPLAY \ +{ \ + .display_name = "LQ057Q3DC12I", \ + .width = 320, \ + .height = 240, \ + .control = LCD_CONTROL_WATERMARK | \ + LCD_CONTROL_PWR | \ + LCD_CONTROL_TFT | \ + LCD_CONTROL_BGR | \ + LCD_CONTROL_BPP_16 | \ + LCD_CONTROL_EN, \ + .timing = { \ + LCD_TIMING0_HBP(8) | \ + LCD_TIMING0_HFP(39) | \ + LCD_TIMING0_HSW(2) | \ + LCD_TIMING0_PPL(320 / 16 - 1),\ + LCD_TIMING1_VBP(6) | \ + LCD_TIMING1_VFP(5) | \ + LCD_TIMING1_VSW(0) | \ + LCD_TIMING1_LPP(240 - 1), \ + LCD_TIMING2_CPL(320 - 1) | \ + LCD_TIMING2_IHS | \ + LCD_TIMING2_IVS, \ + }, \ + .clock = 7000000, \ +} diff --git a/arch/arm/mach-ns9xxx/include/mach/display/LQ064V3DG01.h b/arch/arm/mach-ns9xxx/include/mach/display/LQ064V3DG01.h new file mode 100644 index 000000000000..e801e5f0766e --- /dev/null +++ b/arch/arm/mach-ns9xxx/include/mach/display/LQ064V3DG01.h @@ -0,0 +1,28 @@ + +#define LQ064V3DG01_DISPLAY \ +{ \ + .display_name = "LQ064V3DG01", \ + .width = 640, \ + .height = 480, \ + .control = LCD_CONTROL_WATERMARK | \ + LCD_CONTROL_PWR | \ + LCD_CONTROL_TFT | \ + LCD_CONTROL_BGR | \ + LCD_CONTROL_BPP_16 | \ + LCD_CONTROL_EN, \ + .timing = { \ + LCD_TIMING0_HBP(40) | \ + LCD_TIMING0_HFP(8) | \ + LCD_TIMING0_HSW(96) | \ + LCD_TIMING0_PPL(640 / 16 - 1),\ + LCD_TIMING1_VBP(31) | \ + LCD_TIMING1_VFP(2) | \ + LCD_TIMING1_VSW(2) | \ + LCD_TIMING1_LPP(480 - 1), \ + LCD_TIMING2_CPL(640 - 1) | \ + LCD_TIMING2_IPC | \ + LCD_TIMING2_IHS | \ + LCD_TIMING2_IVS, \ + }, \ + .clock = 28000000, \ +} diff --git a/arch/arm/mach-ns9xxx/include/mach/display/VGA.h b/arch/arm/mach-ns9xxx/include/mach/display/VGA.h new file mode 100644 index 000000000000..63f79f2440a6 --- /dev/null +++ b/arch/arm/mach-ns9xxx/include/mach/display/VGA.h @@ -0,0 +1,29 @@ + +#define VGA_DISPLAY \ +{ \ + .display_name = "VGA", \ + .width = 640, \ + .height = 480, \ + .control = LCD_CONTROL_WATERMARK | \ + LCD_CONTROL_PWR | \ + LCD_CONTROL_TFT | \ + LCD_CONTROL_BGR | \ + LCD_CONTROL_BPP_16 | \ + LCD_CONTROL_EN, \ + .timing = { \ + LCD_TIMING0_HBP(40) | \ + LCD_TIMING0_HFP(8) | \ + LCD_TIMING0_HSW(96) | \ + LCD_TIMING0_PPL(640 / 16 - 1),\ + LCD_TIMING1_VBP(25) | \ + LCD_TIMING1_VFP(2) | \ + LCD_TIMING1_VSW(2) | \ + LCD_TIMING1_LPP(480 - 1), \ + LCD_TIMING2_CPL(640 - 1) | \ + LCD_TIMING2_BCD | \ + LCD_TIMING2_IPC | \ + LCD_TIMING2_IHS | \ + LCD_TIMING2_IVS, \ + }, \ + .clock = 0, /* external */ \ +} diff --git a/arch/arm/mach-ns9xxx/include/mach/display/displays.h b/arch/arm/mach-ns9xxx/include/mach/display/displays.h new file mode 100644 index 000000000000..5fa5ca1de4d6 --- /dev/null +++ b/arch/arm/mach-ns9xxx/include/mach/display/displays.h @@ -0,0 +1,46 @@ +/* + * arch/arm/mach-ns9xxx/displays/displays.h + * + * Copyright (C) 2009 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 <mach/ns9360fb.h> + +#if defined(CONFIG_NS9XXX_FB_VGA) +#include <mach/display/VGA.h> +#endif + +#if defined(CONFIG_NS9XXX_FB_LQ057Q3DC12I) +#include <mach/display/LQ057Q3DC12I.h> +#endif + +#if defined(CONFIG_NS9XXX_FB_LQ064V3DG01) +#include <mach/display/LQ064V3DG01.h> +#endif + +#if defined(CONFIG_NS9XXX_FB_CUSTOM) +#include <mach/display/CUSTOM.h> +#endif + +/* List of supported displays */ +struct ns9360fb_display display_list[] = { +#if defined(CONFIG_NS9XXX_FB_VGA) + VGA_DISPLAY, +#endif +#if defined(CONFIG_NS9XXX_FB_LQ057Q3DC12I) + LQ057Q3DC12I_DISPLAY, +#endif +#if defined(CONFIG_NS9XXX_FB_LQ064V3DG01) + LQ064V3DG01_DISPLAY, +#endif +#if defined(CONFIG_NS9XXX_FB_CUSTOM) + CUSTOM_DISPLAY, +#endif +}; + + diff --git a/arch/arm/mach-ns9xxx/include/mach/dma-ns921x.h b/arch/arm/mach-ns9xxx/include/mach/dma-ns921x.h new file mode 100644 index 000000000000..9fcbee4caa39 --- /dev/null +++ b/arch/arm/mach-ns9xxx/include/mach/dma-ns921x.h @@ -0,0 +1,140 @@ +/* + * arch/arm/mach-ns9xxx/include/mach/dma-ns921x.h + * + * Copyright (C) 2009 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. + * + */ + + +#ifndef __ASM_ARCH_NS921X_DMA_H +#define __ASM_ARCH_NS921X_DMA_H + +#include <mach/hardware.h> + +/* External DMA control nad status registers. Valid channels are 1 and 2 */ +#define NS921X_DMA_BDP(x) __REG(0xa0800000 + ((x-1) & 0x1) * 0x10) +#define NS921X_DMA_CR(x) __REG(0xa0800004 + ((x-1) & 0x1) * 0x10) +#define NS921X_DMA_STIE(x) __REG(0xa0800008 + ((x-1) & 0x1) * 0x10) +#define NS921X_DMA_PCS(x) __REG(0xa080000c + ((x-1) & 0x1) * 0x10) + +/* Control register masks */ +#define NS921X_DMA_CR_CE (0x1 << 31) +#define NS921X_DMA_CR_CA (0x1 << 30) +#define NS921X_DMA_CR_CG (0x1 << 29) +#define NS921X_DMA_CR_SW_MA (0x3 << 27) +#define NS921X_DMA_CR_SW_8b (0x0 << 27) +#define NS921X_DMA_CR_SW_16b (0x1 << 27) +#define NS921X_DMA_CR_SW_32b (0x2 << 27) +#define NS921X_DMA_CR_DW_MA (0x3 << 25) +#define NS921X_DMA_CR_DW_8b (0x0 << 25) +#define NS921X_DMA_CR_DW_16b (0x1 << 25) +#define NS921X_DMA_CR_DW_32b (0x2 << 25) +#define NS921X_DMA_CR_SB_MA (0x3 << 23) +#define NS921X_DMA_CR_SB_1B (0x0 << 23) +#define NS921X_DMA_CR_SB_4B (0x1 << 23) +#define NS921X_DMA_CR_SB_16B (0x2 << 23) +#define NS921X_DMA_CR_SB_32B (0x3 << 23) +#define NS921X_DMA_CR_DB_MA (0x3 << 21) +#define NS921X_DMA_CR_DB_1B (0x0 << 21) +#define NS921X_DMA_CR_DB_4B (0x1 << 21) +#define NS921X_DMA_CR_DB_16B (0x2 << 21) +#define NS921X_DMA_CR_DB_32B (0x3 << 21) +#define NS921X_DMA_CR_SINC_N (0x1 << 20) +#define NS921X_DMA_CR_DINC_N (0x1 << 19) +#define NS921X_DMA_CR_POL (0x1 << 18) +#define NS921X_DMA_CR_MODE (0x1 << 17) +#define NS921X_DMA_CR_MODE_FBW (0x0 << 17) +#define NS921X_DMA_CR_MODE_FBR (0x1 << 17) +#define NS921X_DMA_CR_RESET (0x1 << 16) +#define NS921X_DMA_CR_STATE_MA (0x3f << 10) +#define NS921X_DMA_CR_INDEX_MA (0x3ff << 0) + +/* Status and interrupt enable masks */ +#define NS921X_DMA_STIE_NCIP (0x1 << 31) +#define NS921X_DMA_STIE_ECIP (0x1 << 30) +#define NS921X_DMA_STIE_NRIP (0x1 << 29) +#define NS921X_DMA_STIE_CAIP (0x1 << 28) +#define NS921X_DMA_STIE_PCIP (0x1 << 27) +#define NS921X_DMA_STIE_NCIE (0x1 << 24) +#define NS921X_DMA_STIE_ECIE (0x1 << 23) +#define NS921X_DMA_STIE_NRIE (0x1 << 22) +#define NS921X_DMA_STIE_CAIE (0x1 << 21) +#define NS921X_DMA_STIE_PCIE (0x1 << 20) +#define NS921X_DMA_STIE_IE_ALL (0x1f << 20) +#define NS921X_DMA_STIE_WRAP (0x1 << 19) +#define NS921X_DMA_STIE_DONE (0x1 << 18) +#define NS921X_DMA_STIE_LAST (0x1 << 17) +#define NS921X_DMA_STIE_FULL (0x1 << 16) +#define NS921X_DMA_STIE_BLEN_MA (0xffff << 0) + +/* Peripheral CS register */ +#define NS921X_DMA_PCS_SEL_MA (0x3 << 0) +#define NS921X_DMA_PCS_CS0 (0x0 << 0) +#define NS921X_DMA_PCS_CS1 (0x1 << 0) +#define NS921X_DMA_PCS_CS2 (0x2 << 0) +#define NS921X_DMA_PCS_CS3 (0x3 << 0) + +#define EXT_DMA_DESC_CTRL_WRAP (0x1 << 15) +#define EXT_DMA_DESC_CTRL_INT (0x1 << 14) +#define EXT_DMA_DESC_CTRL_LAST (0x1 << 13) +#define EXT_DMA_DESC_CTRL_FULL (0x1 << 12) +#define EXT_DMA_DESC_CTRL_ALL (EXT_DMA_DESC_CTRL_FULL | \ + EXT_DMA_DESC_CTRL_INT | \ + EXT_DMA_DESC_CTRL_LAST | \ + EXT_DMA_DESC_CTRL_WRAP) + +struct ext_dma_desc_t { + unsigned int src; + unsigned int length; + unsigned int dest; + unsigned short status; + unsigned short control; +}__attribute__((__packed__)); + + +/* + * IO-HUB constans and macros + * The maximal number of DMA-buffer descriptors comes from the NET+OS + * distribution (iop_private.h) + */ +#define IOHUB_MAX_DMA_BUFFERS (64) +#define IOHUB_MAX_DMA_LENGTH (65535) + +#define IOHUB_DMA_DESC_CTRL_WRAP EXT_DMA_DESC_CTRL_WRAP +#define IOHUB_DMA_DESC_CTRL_INT EXT_DMA_DESC_CTRL_INT +#define IOHUB_DMA_DESC_CTRL_LAST EXT_DMA_DESC_CTRL_LAST +#define IOHUB_DMA_DESC_CTRL_FULL EXT_DMA_DESC_CTRL_FULL +#define IOHUB_DMA_DESC_CTRL_ALL EXT_DMA_DESC_CTRL_ALL + +struct iohub_dma_desc_t { + unsigned int src; + unsigned int length; + unsigned int reserved; + unsigned short status; + unsigned short control; +}__attribute__((packed, aligned)); + + +#define IOHUB_DMA_DESC_LENGTH sizeof(struct iohub_dma_desc_t) + +/* This is the FIFO used for the DMA-transfers of the IOHUB (e.g. FIMs) */ +struct iohub_dma_fifo_t { + int length; + struct iohub_dma_desc_t **descs; + dma_addr_t phys_descs; + struct iohub_dma_desc_t *first; + struct iohub_dma_desc_t *last; + struct iohub_dma_desc_t *dma_first; + struct iohub_dma_desc_t *dma_last; + struct iohub_dma_desc_t *dma_next; + struct iohub_dma_desc_t *next_free; + unsigned long rx_error, tx_error; + unsigned long rx_error1, tx_error2; +}__attribute__((__packed__)); + +#endif /* ifndef __ASM_ARCH_NS912X_DMA_H */ diff --git a/arch/arm/mach-ns9xxx/include/mach/fim-firmware.h b/arch/arm/mach-ns9xxx/include/mach/fim-firmware.h new file mode 100644 index 000000000000..6bdd0e05333d --- /dev/null +++ b/arch/arm/mach-ns9xxx/include/mach/fim-firmware.h @@ -0,0 +1,101 @@ +/* + * arch/arm/mach-ns9xxx/include/mach/fim-firmware.h + * + * Copyright (C) 2006 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. + * + * !Revision: $Revision: 1.0 $ + * !Author: Luis Galdos + * !Desc: + * !References: + */ + + +#ifndef _FIM_FIRMWARE_H +#define _FIM_FIRMWARE_H + + + +#define FIM_NUM_HWA_CONF_REGS (14) +#define FIM_NS9215_MAX_INSTRUCTIONS (1024) + + +typedef enum { + FIM_NS9215 = 0, +} fim_processors_t; + +#define PROCESSOR_TYPE_VALID(t) (t == FIM_NS9215) /* || (t == ADD_NEW_ONE_HERE) */ + + +typedef enum { + FIM_FORMAT_0 = 0, +} fim_formats_t; + +#define FORMAT_TYPE_VALID(t) (t == FIM_FORMAT_0) /* || (t == ADD_NEW_ONE_HERE) */ + +typedef enum { + FIM_PROCESSOR_PIC0, + FIM_PROCESSOR_PIC1 +} fim_processor_index_t; + +typedef enum { + FIM_HW_ASSIST_MODE_NONE, + FIM_HW_ASSIST_MODE_GENERIC, + FIM_HW_ASSIST_MODE_CAN, +} fim_hw_assit_t; + +typedef enum { + FIM_CLK_DIV_2, + FIM_CLK_DIV_4, + FIM_CLK_DIV_8, + FIM_CLK_DIV_16, + FIM_CLK_DIV_32, + FIM_CLK_DIV_64, + FIM_CLK_DIV_128, + FIM_CLK_DIV_256 +} fim_output_clk_div_t; + +typedef enum { + FIM_SIGBUS_SIGNAL_0, + FIM_SIGBUS_SIGNAL_1, + FIM_SIGBUS_SIGNAL_2, + FIM_SIGBUS_SIGNAL_3, + FIM_SIGBUS_SIGNAL_4, + FIM_SIGBUS_SIGNAL_5, + FIM_SIGBUS_SIGNAL_6, + FIM_SIGBUS_SIGNAL_7, + FIM_SIGBUS_CONTROL_0, + FIM_SIGBUS_CONTROL_1, + FIM_SIGBUS_CONTROL_2, + FIM_SIGBUS_CONTROL_3, + FIM_SIGBUS_16_BIT_BUS, + FIM_SIGBUS_24_BIT_BUS +} fim_signal_bus_t; + + + +/* + * The macro FIM_FIRMWARE_BUILDER is set by the build-system of the FIM-firmware + * See the Makefile under ../firmware/Makefile for more infos. + */ +struct fim_program_t { + fim_processors_t processor; + fim_formats_t format; + fim_hw_assit_t hw_mode; + fim_output_clk_div_t clkdiv; + unsigned int hwa_cfg[FIM_NUM_HWA_CONF_REGS]; + unsigned int length; +#ifndef FIM_FIRMWARE_BUILDER + unsigned short data[FIM_NS9215_MAX_INSTRUCTIONS]; +#endif +} __attribute__((packed, aligned)); + + +#endif /* _FIM_FIRMWARE_H */ + + + diff --git a/arch/arm/mach-ns9xxx/include/mach/fim-ns921x.h b/arch/arm/mach-ns9xxx/include/mach/fim-ns921x.h new file mode 100644 index 000000000000..6fbc61488f32 --- /dev/null +++ b/arch/arm/mach-ns9xxx/include/mach/fim-ns921x.h @@ -0,0 +1,466 @@ +/* -*- linux-c -*- + * arch/arm/mach-ns9xxx/include/mach/fim-ns921x.h + * + * 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. + * + * !Revision: $Revision: 1.25 $ + * !Author: Silvano Najera, Luis Galdos + * !Descr: + * !References: + */ + + +#ifndef _NS921X_FIM_CORE_H +#define _NS921X_FIM_CORE_H + + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/firmware.h> +#include <linux/platform_device.h> +#include <linux/kfifo.h> +#include <linux/list.h> +#include <linux/interrupt.h> + +#include <mach/dma-ns921x.h> + + +#define FIM_MAX_FIRMWARE_NAME 32 + + +/* For DMA handling... */ +#define FIM_DMA_NCIP (0x1) +#define FIM_DMA_NRIP (0x2) +#define FIM_DMA_ECIP (0x4) +#define FIM_DMA_CAIP (0x8) +#define FIM_DMA_CANCELLED FIM_DMA_CAIP +#define FIM_DMA_FLUSHED (0x10) +#define FIM_DMA_SUCCESS (FIM_DMA_NCIP | FIM_DMA_NRIP) + + +#define FIM_MAX_PIC_INDEX (1) +#define FIM_MIN_PIC_INDEX (0) +#define FIM_NR_PICS (FIM_MAX_PIC_INDEX-FIM_MIN_PIC_INDEX+1) + + +/* @XXX: Place this macros in another place? */ +#define NS92XX_FIM_GEN_CTRL_STOP_PIC ~NS92XX_FIM_GEN_CTRL_PROGMEM +#define NS92XX_FIM_GEN_CTRL_START_PIC NS92XX_FIM_GEN_CTRL_PROGMEM + + + +/* Please note that the maximal DMA-buffer size is 64kB */ +/* @FIXME: Check that the maximal size of the descriptors is littler than one page */ +#define PIC_DMA_RX_BUFFERS (10) +#define PIC_DMA_TX_BUFFERS (10) +#define PIC_DMA_BUFFER_SIZE (1 * PAGE_SIZE) + +/* + * Internal structure for handling with the DMA-buffer descriptors + * p_desc : Physical descriptors address + * v_desc : Virtual access address for the descriptors + * v_buf : Virtual address of the memory buffers + * length : Configured length of this buffer + * tasked : Used for locking the descriptor + */ +struct pic_dma_desc_t { + dma_addr_t src; + size_t length; + atomic_t tasked; + void *private; + int total_length; +}; + + +/* + * Structure used by the FIM-API to configure the DMA-buffer and buffer-descriptors. + * rxnr : Number of RX-DMA-buffers + * rxsz : Size of each DMA-buffer (in Bytes) + * txnr : Number of TX-DMA-buffers + * txsz : Size for each TX-buffer (in Bytes) + */ +struct fim_dma_cfg_t { + int rxnr; + int rxsz; + int txnr; + int txsz; +}; + + +/* + * This structure should be used for transferring data with the API + * length : Date length to transfer + * data : Data buffer + * private : The API will not touch this pointer + * sent : The external driver can use it for waking up sleeping processes + */ +struct fim_buffer_t { + int length; + unsigned char *data; + void *private; + int sent; +}; + + +/* @TODO: We need perhaps another PIC-structure for the U-Boot */ +struct pic_t { + int irq; + struct device *dev; + struct fim_driver *driver; + void __iomem *reg_addr; + void __iomem *instr_addr; + void __iomem *hwa_addr; + void __iomem *iohub_addr; + spinlock_t lock; + int index; + atomic_t irq_enabled; + atomic_t requested; + + /* RX-DMA structures */ + struct iohub_dma_fifo_t rx_fifo; + spinlock_t rx_lock; + struct fim_dma_cfg_t dma_cfg; + + /* Variables for the DMA-memory buffers */ + dma_addr_t dma_phys; + void __iomem *dma_virt; + size_t dma_size; + + /* Data for the handling of the TX-DMA buffers */ + spinlock_t tx_lock; + struct pic_dma_desc_t *tx_desc; + struct iohub_dma_fifo_t tx_fifo; + atomic_t tx_tasked; + atomic_t tx_aborted; + struct tasklet_struct rx_tasklet; + + /* Info data for the sysfs */ + char fw_name[FIM_MAX_FIRMWARE_NAME]; + int fw_length; + + /* Functions for a low level access to the PICs */ + int (* is_running)(struct pic_t *); + int (* start_at_zero)(struct pic_t *); + int (* stop_and_reset)(struct pic_t *); + int (* download_firmware)(struct pic_t *, const unsigned char *); + int (* get_ctrl_reg)(struct pic_t *, int , unsigned int *); + void (* set_ctrl_reg)(struct pic_t *, int , unsigned int ); + int (* send_interrupt)(struct pic_t *, u32 ); + void (* ack_interrupt)(struct pic_t * , int ); +}; + + +/* + * Structure with the GPIOs to use for the driver to be initialized + * nr : GPIO number + * name : Name to use for the GPIO + * picval : Value to pass to the PIC-firmware + * func : Function to be configured for the GPIO + */ +struct fim_gpio_t { + int nr; + char *name; + unsigned char picval; /* Value to pass to firmware */ + unsigned int func; +}; + +#define FIM_LAST_GPIO -2 +#define FIM_GPIO_DONT_USE -1 + +/* + * Internal structure for allocating a FIM driver + * picnr : Number of the PIC to use for this driver + * fw_code : Firmware code that should be used as firmware + * fw_name : Name of the firmware to get over the firmware layer + * driver : Driver structure + * dev : Device that should be set by the FIM-API + * driver_data : The API will not touch this member + * fim_isr : Called when the PIC generates an interrupt + * dma_tx_isr : TX-callback function. Called in interrupt context + * dma_rx_isr : RX-callback. Called inside the interrupt context + * dma_cfg : If NULL then the API will use the default config + * verbose : Used by the FIM-core for printing sys messages (debug, infos, etc.) + */ +struct fim_driver { + int picnr; + const unsigned char *fw_code; + const char *fw_name; + struct device_driver driver; + struct device *dev; + void (*fim_isr)(struct fim_driver *, int, unsigned char, unsigned int); + void (*dma_tx_isr)(struct fim_driver *, int, struct fim_buffer_t *); + void (*dma_rx_isr)(struct fim_driver *, int, struct fim_buffer_t *); + void (*dma_error_isr)(struct fim_driver *, ulong rx_err, ulong tx_err); + void *driver_data; + struct fim_dma_cfg_t *dma_cfg; + int verbose; +}; + + + +/* + * Structure for the FIM-devices with UART-support + * If a GPIO should not be used, then it's required to disable it by using the + * above macro 'FIM_GPIO_DONT_USE' + * + * fim_nr : Number of the FIM to use for the device + * gpio_nr : GPIO to use for the interface line + * fim_cfg : Currently not used + */ +struct fim_serial_platform_data { + int fim_nr; + + int rx_gpio_nr; + unsigned int rx_gpio_func; + unsigned int rx_fim_cfg; + + int tx_gpio_nr; + unsigned int tx_gpio_func; + unsigned int tx_fim_cfg; + + int cts_gpio_nr; + unsigned int cts_gpio_func; + unsigned int cts_fim_cfg; + + int rts_gpio_nr; + unsigned int rts_gpio_func; + unsigned int rts_fim_cfg; +}; + + +/* Macro for the configuration of the GPIOs for the FIM-serial driver */ +#define NS921X_FIM_SERIAL_GPIOS(rx, tx, rts, cts, func) \ + .rx_gpio_nr = rx, \ + .rx_gpio_func = func, \ + .tx_gpio_nr = tx, \ + .tx_gpio_func = func, \ + .rts_gpio_nr = rts, \ + .rts_gpio_func = func, \ + .cts_gpio_nr = cts, \ + .cts_gpio_func = func + + +/* + * Structure for the FIM-devices with SDIO-support + * If a GPIO should not be used, then it's required to disable it by using the + * macro 'FIM_GPIO_DONT_USE' + * + * fim_nr : Number of the FIM to use for the device + * host_caps : Specific host capabilities (see: linux/mmc/host.h) + */ +struct fim_sdio_platform_data { + int fim_nr; + unsigned int host_caps; /* Host capabilities */ + + int d0_gpio_nr; /* data 0 */ + unsigned int d0_gpio_func; + int d1_gpio_nr; /* data 1 */ + unsigned int d1_gpio_func; + int d2_gpio_nr; /* data 2 */ + unsigned int d2_gpio_func; + int d3_gpio_nr; /* data 3 */ + unsigned int d3_gpio_func; + int wp_gpio_nr; /* write protect */ + unsigned int wp_gpio_func; + int cd_gpio_nr; /* card detect */ + unsigned int cd_gpio_func; + int clk_gpio_nr; /* clock */ + unsigned int clk_gpio_func; + int cmd_gpio_nr; /* command */ + unsigned int cmd_gpio_func; +}; + + +/* + * Use the below macro if all the GPIOs can be configured with the same function + * number (this is the normal case) + */ +#define NS921X_FIM_SDIO_GPIOS(d0, d1, d2, d3, wp, cd, clk, cmd, func) \ + .d0_gpio_nr = d0, \ + .d0_gpio_func = func, \ + .d1_gpio_nr = d1, \ + .d1_gpio_func = func, \ + .d2_gpio_nr = d2, \ + .d2_gpio_func = func, \ + .d3_gpio_nr = d3, \ + .d3_gpio_func = func, \ + .wp_gpio_nr = wp, \ + .wp_gpio_func = func, \ + .cd_gpio_nr = cd, \ + .cd_gpio_func = func, \ + .clk_gpio_nr = clk, \ + .clk_gpio_func = func, \ + .cmd_gpio_nr = cmd, \ + .cmd_gpio_func = func + +/* + * The new FIM board doesn't connect all the lines to the FIM. The CMD + * and CD are not connected to the FIM. + */ +#define NS921X_FIM_SDIO_GPIOS_FIM(d0, d1, d2, d3, clk, cmd, func) \ + .d0_gpio_nr = d0, \ + .d0_gpio_func = func, \ + .d1_gpio_nr = d1, \ + .d1_gpio_func = func, \ + .d2_gpio_nr = d2, \ + .d2_gpio_func = func, \ + .d3_gpio_nr = d3, \ + .d3_gpio_func = func, \ + .clk_gpio_nr = clk, \ + .clk_gpio_func = func, \ + .cmd_gpio_nr = cmd, \ + .cmd_gpio_func = func + +/* + * Structure for the FIM-devices with CAN-support + * If a GPIO should not be used, then it's required to disable it by using the + * above macro 'FIM_GPIO_DONT_USE' + * + * fim_nr : Number of the FIM to use for the device + * gpio_nr : GPIO to use for the interface line + */ +struct fim_can_platform_data { + + int fim_nr; + int fim_can_bitrate; + + int rx_gpio_nr; + unsigned int rx_gpio_func; + int tx_gpio_nr; + unsigned int tx_gpio_func; +}; + +/* Macro for the configuration of the GPIOs for the FIM CAN driver */ +#define NS921X_FIM_CAN_GPIOS(rx, tx, func) \ + .rx_gpio_nr = rx, \ + .rx_gpio_func = func, \ + .tx_gpio_nr = tx, \ + .tx_gpio_func = func + +/* + * Structure for the FIM-devices with USB support + * If a GPIO should not be used, then it's required to disable it by using the + * above macro 'FIM_GPIO_DONT_USE' + * + * fim_nr : Number of the FIM to use for the device + * gpio_nr : GPIO to use for the interface line + */ +struct fim_usb_platform_data { + + int fim_nr; + + int (*init)(struct device *); + int (*exit)(struct device *); + + int vp_gpio_nr; + unsigned int vp_gpio_func; + int vm_gpio_nr; + unsigned int vm_gpio_func; + int rcv_gpio_nr; + unsigned int rcv_gpio_func; + int oe_l_gpio_nr; + unsigned int oe_l_gpio_func; + int enum_gpio_nr; + unsigned int enum_gpio_func; + int spnd_gpio_nr; + unsigned int spnd_gpio_func; +}; + +/* + * Macro for the configuration of the GPIOs for the FIM USB driver + * IMPORTANT: The FIM-firmware is able to control the DP, DM, OE and RCV pins, but NOT + * the lines for the enumeration (ENUM) and suspend (SPND). The 'func_out' defines the + * function for the output GPIOs + */ +#define NS921X_FIM_USB_GPIOS(vp, vm, rcv, oe_l, enume, spnd, func, func_out) \ + .vp_gpio_nr = vp, \ + .vp_gpio_func = func, \ + .vm_gpio_nr = vm, \ + .vm_gpio_func = func, \ + .rcv_gpio_nr = rcv, \ + .rcv_gpio_func = func, \ + .oe_l_gpio_nr = oe_l, \ + .oe_l_gpio_func = func, \ + .enum_gpio_nr = enume, \ + .enum_gpio_func = func_out, \ + .spnd_gpio_nr = spnd, \ + .spnd_gpio_func = func_out + +/* Macros for building the FIM-drivers as loadable modules */ +#if defined(MODULE) +# define NS921X_FIM_NUMBERS_PARAM(number) \ + static int number = -1; \ + module_param_named(fims, number, int, 0644); +#else +# define NS921X_FIM_NUMBERS_PARAM(number) \ + static int number = FIM_NR_PICS; +#endif + +/* Call the function for checking the FIM module parameter */ +#if defined(MODULE) +inline int fim_check_numbers_param(int number) \ +{ \ + if (number < 0 || number > FIM_NR_PICS) \ + return -1; \ + else \ + return 0; \ +} +inline int fim_check_device_id(int number, uint id) { \ + int ret; \ + if (id < 0) \ + ret = 1; \ + else if (number == FIM_NR_PICS && id < number) \ + ret = 0; \ + else if (number < FIM_NR_PICS && id == number) \ + ret = 0; \ + else \ + ret = 1; \ + return ret; \ +} +#else +# define fim_check_numbers_param(number) (0) +# define fim_check_device_id(number, id) (id < 0 || id >= number) +#endif + +/* These are the functions of the FIM-API */ +int fim_register_driver(struct fim_driver *driver); +int fim_unregister_driver(struct fim_driver *driver); +int fim_send_interrupt2(struct fim_driver *driver, unsigned int code); +int fim_get_exp_reg(struct fim_driver *driver, int nr, unsigned int *value); +int fim_enable_irq(struct fim_driver *driver); +int fim_disable_irq(struct fim_driver *driver); +int fim_send_buffer(struct fim_driver *driver, const struct fim_buffer_t *bufdesc); +int fim_tx_buffers_room(struct fim_driver *driver); +int fim_tx_buffers_level(struct fim_driver *driver); +int fim_send_reset(struct fim_driver *driver); +int fim_send_start(struct fim_driver *driver); +int fim_send_stop(struct fim_driver *driver); +void fim_flush_rx(struct fim_driver *driver); +void fim_flush_tx(struct fim_driver *driver); +struct fim_buffer_t *fim_alloc_buffer(struct fim_driver *driver, int length, + unsigned int gfp_flags); +void fim_free_buffer(struct fim_driver *driver, struct fim_buffer_t *buffer); +void fim_set_ctrl_reg(struct fim_driver *driver, int reg, unsigned int val); +void fim_set_exp_reg(struct fim_driver *driver, int reg, unsigned int val); +int fim_get_ctrl_reg(struct fim_driver *driver, int reg, unsigned int *val); +int fim_get_stat_reg(struct fim_driver *driver, int reg, unsigned int *val); +struct pic_t *fim_request_pic(int picnr); +void fim_free_pic(struct pic_t *pic); +void fim_print_fifo_status(struct fim_driver *driver); +int fim_number_pics(void); +int fim_download_firmware(struct fim_driver *driver); +int fim_is_running(struct fim_driver *driver); + +int fim_dma_stop(struct fim_driver *fim); +int fim_dma_start(struct fim_driver *fim, struct fim_dma_cfg_t *cfg); + +#endif /* ifndef _NS921X_FIM_CORE_H */ + + + diff --git a/arch/arm/mach-ns9xxx/include/mach/fim-uncompress.h b/arch/arm/mach-ns9xxx/include/mach/fim-uncompress.h new file mode 100644 index 000000000000..0f77d72bbc5d --- /dev/null +++ b/arch/arm/mach-ns9xxx/include/mach/fim-uncompress.h @@ -0,0 +1,93 @@ +/* -*- linux-c -*- + * + * arch/arm/mach-ns9xxx/include/mach/fim-uncompress.h + * + * Copyright (C) 2009 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. + * + * !Authors: Hector Palacios, Luis Galdos + * !Desc: + * !References: + */ + +#ifndef __FIM_UNCROMPRESS_H +#define __FIM_UNCROMPRESS_H + +#include <asm/io.h> + +#define NS921X_FIM0 __REG(0x90000000) +#define NS921X_FIM1 __REG(0x90008000) + +#define FIM_SERIAL_DATA_BITS (8) + +#define NS92XX_FIM_CTRL0_REG (0x10) +#define NS92XX_FIM_EXP0_REG (0x50) +#define NS92XX_FIM_CTRL_REG(i) (NS92XX_FIM_CTRL0_REG + 4*i) +#define NS92XX_FIM_EXP_REG(i) (NS92XX_FIM_EXP0_REG + 4*i) + +#define NS92XX_FIM_REG_BASE_PA (0x90001000) +#define NS92XX_FIM_REG_BASE_PA (0x90001000) +#define NS92XX_FIM_REG_OFFSET (0x8000) +#define FIM_REG_ADDR(x) (NS92XX_FIM_REG_BASE_PA + \ + (x * NS92XX_FIM_REG_OFFSET)) +#define NS921X_FIM_ENABLED(base) (__raw_readl((base) + 0x1000) \ + & (1 << 31)) +#define NS92XX_FIM_GEN_CTRL_REG (0x00) +#define NS92XX_FIM_GEN_CTRL_INTTOPIC (0x00007f00) +#define NS92XX_FIM_GEN_CTRL_INTACKRD (0x00000080) +#define NS92XX_FIM_INT_MASK(code) (code<<8) + +#define FIM_SERIAL_INT_INSERT_CHAR (0x01) + +static int fim_send_interrupt(int pic_num, unsigned int code) +{ + unsigned int stopcnt; + u32 status; + + code = NS92XX_FIM_INT_MASK(code); + status = readl(FIM_REG_ADDR(pic_num) + NS92XX_FIM_GEN_CTRL_REG); + writel(status | code, FIM_REG_ADDR(pic_num) + NS92XX_FIM_GEN_CTRL_REG); + + /* This loop is perhaps problematic, exit with a timeout */ + stopcnt = 0xFFFF; + do { + status = readl(FIM_REG_ADDR(pic_num) + NS92XX_FIM_GEN_CTRL_REG); + stopcnt--; + } while (!(status & NS92XX_FIM_GEN_CTRL_INTACKRD) && stopcnt); + + if (!stopcnt) { + return 1; + } + + /* Reset the interrupt bits for the PIC acknowledge */ + status &= ~NS92XX_FIM_GEN_CTRL_INTTOPIC; + writel(status, FIM_REG_ADDR(pic_num) + NS92XX_FIM_GEN_CTRL_REG); + + stopcnt = 0xFFFF; + do { + status = readl(FIM_REG_ADDR(pic_num) + NS92XX_FIM_GEN_CTRL_REG); + stopcnt--; + } while ((status & NS92XX_FIM_GEN_CTRL_INTACKRD) && stopcnt); + + if (!stopcnt) { + return 1; + } + + return 0; +} + +static void fim_set_ctrl_reg(int pic_num, int reg, unsigned int val) +{ + writel(val, FIM_REG_ADDR(pic_num) + NS92XX_FIM_CTRL_REG(reg)); +} + +static int fim_get_exp_reg(int pic_num, int nr) +{ + return readl(FIM_REG_ADDR(pic_num) + NS92XX_FIM_EXP_REG(nr)); +} + +#endif /* __FIM_UNCROMPRESS_H */ diff --git a/arch/arm/mach-ns9xxx/include/mach/gpio.h b/arch/arm/mach-ns9xxx/include/mach/gpio.h index 5eb349032579..40e246dabdcc 100644 --- a/arch/arm/mach-ns9xxx/include/mach/gpio.h +++ b/arch/arm/mach-ns9xxx/include/mach/gpio.h @@ -1,7 +1,7 @@ /* * arch/arm/mach-ns9xxx/include/mach/gpio.h * - * Copyright (C) 2007 by Digi International Inc. + * Copyright (C) 2007,2008 by Digi International Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify it @@ -11,21 +11,457 @@ #ifndef __ASM_ARCH_GPIO_H #define __ASM_ARCH_GPIO_H +#include <linux/spinlock.h> #include <asm/errno.h> +#include <asm/io.h> +#include <mach/hardware.h> +#include <mach/processor.h> -int gpio_request(unsigned gpio, const char *label); +#include <mach/regs-io-ns921x.h> +#include <mach/regs-bbu.h> + + +/* Macros for configuring the GPIO-functions */ +#if defined(CONFIG_PROCESSOR_NS9210) || defined(CONFIG_PROCESSOR_NS9215) +# define NS921X_GPIO_FUNC_0 (0x00) +# define NS921X_GPIO_FUNC_1 (0x01) +# define NS921X_GPIO_FUNC_2 (0x02) +# define NS921X_GPIO_FUNC_3 (0x03) +# define NS921X_GPIO_FUNC_4 (0x04) + +# define NS921X_GPIO_FUNC_GPIO NS921X_GPIO_FUNC_3 + +# define NS921X_GPIO_INPUT (0x00) +# define NS921X_GPIO_OUTPUT (0x01) + +# define NS921X_GPIO_INVERT (0x01) +# define NS921X_GPIO_DONT_INVERT (0x00) + +# define NS921X_GPIO_ENABLE_PULLUP (0x00) +# define NS921X_GPIO_DISABLE_PULLUP (0x01) +#endif + +/* Macros for configuring the GPIO-functions */ +#if defined(CONFIG_PROCESSOR_NS9360) +# define NS9360_GPIO_FUNC_0 (0x00) +# define NS9360_GPIO_FUNC_1 (0x01) +# define NS9360_GPIO_FUNC_2 (0x02) +# define NS9360_GPIO_FUNC_3 (0x03) +# define NS9360_GPIO_FUNC_4 (0x04) + +# define NS9360_GPIO_FUNC_GPIO NS9360_GPIO_FUNC_3 + +# define NS9360_GPIO_INPUT (0x00) +# define NS9360_GPIO_OUTPUT (0x01) + +# define NS9360_GPIO_INVERT (0x01) +# define NS9360_GPIO_DONT_INVERT (0x00) +#endif + + +struct gpio_to_irq_map { + unsigned gpio; + unsigned irq; + int func; +}; + +#define NS9XXX_NUM_GPIO 0 + +#if defined(CONFIG_PROCESSOR_NS9210) +# define NS9XXX_NUM_GPIO_NS9210 108 +# if NS9XXX_NUM_GPIO < NS9XXX_NUM_GPIO_NS9210 +# undef NS9XXX_NUM_GPIO +# define NS9XXX_NUM_GPIO NS9XXX_NUM_GPIO_NS9210 +# endif +static inline int gpio_issocgpio_ns9210(unsigned gpio) +{ + return gpio < NS9XXX_NUM_GPIO_NS9210 && !(gpio >= 50 && gpio < 105); +} +#endif + +#if defined(CONFIG_PROCESSOR_NS9215) +# define NS9XXX_NUM_GPIO_NS9215 108 +# if NS9XXX_NUM_GPIO < NS9XXX_NUM_GPIO_NS9215 +# undef NS9XXX_NUM_GPIO +# define NS9XXX_NUM_GPIO NS9XXX_NUM_GPIO_NS9215 +# endif +static inline int gpio_issocgpio_ns9215(unsigned gpio) +{ + return gpio < NS9XXX_NUM_GPIO_NS9215; +} +#endif + +static const inline struct gpio_to_irq_map *gpio_get_map(unsigned gpio, + const struct gpio_to_irq_map map[], size_t array_size) +{ + /* TODO: check if a binary search yields some performance advantage */ + int i; + + for (i = 0; i < array_size; ++i) { + if (map[i].gpio == gpio) + return &map[i]; + } + + return NULL; +} + +#if defined(CONFIG_PROCESSOR_NS921X) +const struct gpio_to_irq_map *gpio_get_map_ns921x(unsigned gpio) __attribute__((const)); + +static inline void gpio_configure_ns921x_unlocked(unsigned gpio, + int dir, int inv, int func, int dispullup) +{ + void __iomem *conf = NS921X_IO_GPIOCONFx(gpio / 4); + u32 confval; + + confval = __raw_readl(conf); + REGSETIM_IDX(confval, NS921X_IO_GPIOCONFx, DIR, gpio & 3, dir); + REGSETIM_IDX(confval, NS921X_IO_GPIOCONFx, INV, gpio & 3, inv); + REGSETIM_IDX(confval, NS921X_IO_GPIOCONFx, FUNC, gpio & 3, func); + if (gpio != 9 && gpio != 12 && (gpio < 102 || gpio > 105)) + REGSETIM_IDX(confval, NS921X_IO_GPIOCONFx, PUEN, gpio & 3, dispullup); + else { + if (dispullup) + pr_warning("cannot disable pullup for gpio %u\n", gpio); + + REGSETIM_IDX(confval, NS921X_IO_GPIOCONFx, PUEN, gpio & 3, 0); + } + + __raw_writel(confval, conf); +} + +static inline void gpio_configure_ns921x(unsigned gpio, + int dir, int inv, int func, int dispullup) +{ + unsigned long flags; + + local_irq_save(flags); + + gpio_configure_ns921x_unlocked(gpio, dir, inv, func, dispullup); + + local_irq_restore(flags); +} + +static inline int gpio_get_value_ns921x(unsigned gpio) +{ + void __iomem *stat = NS921X_IO_GPIOSTATx(gpio / 32); + + return (__raw_readl(stat) >> (gpio & 31)) & 1; +} + +static inline void gpio_set_value_ns921x_unlocked(unsigned gpio, int value) +{ + void __iomem *ctrl = NS921X_IO_GPIOCTRLx(gpio / 32); + u32 ctrlval; + + ctrlval = __raw_readl(ctrl); + + if (value) + ctrlval |= 1 << (gpio & 31); + else + ctrlval &= ~(1 << (gpio & 31)); + + __raw_writel(ctrlval, ctrl); +} + +static inline int gpio_direction_input_ns921x_unlocked(unsigned gpio) +{ + gpio_configure_ns921x_unlocked(gpio, 0, 0, 3, 0); + return 0; +} + +static inline int gpio_direction_irqinput_ns921x_unlocked(unsigned gpio) +{ + const struct gpio_to_irq_map *map = gpio_get_map_ns921x(gpio); + + if (map) { + gpio_configure_ns921x_unlocked(gpio, 0, 0, map->func, 0); + return 0; + } else + return gpio_direction_input_ns921x_unlocked(gpio); +} + +static inline int gpio_direction_output_ns921x_unlocked(unsigned gpio, + int value) +{ + gpio_set_value_ns921x_unlocked(gpio, value); + gpio_configure_ns921x_unlocked(gpio, 1, 0, 3, 0); + return 0; +} + +#endif /* if defined(CONFIG_PROCESSOR_NS921X) */ + +#if defined(CONFIG_PROCESSOR_NS9360) +# define NS9XXX_NUM_GPIO_NS9360 73 +# if NS9XXX_NUM_GPIO < NS9XXX_NUM_GPIO_NS9360 +# undef NS9XXX_NUM_GPIO +# define NS9XXX_NUM_GPIO NS9XXX_NUM_GPIO_NS9360 +# endif +static inline void __iomem *gpio_ns9360_gstataddr(unsigned gpio) +{ + if (gpio < 32) + return NS9360_BBU_GSTAT1; + else if (gpio < 64) + return NS9360_BBU_GSTAT2; + else + return NS9360_BBU_GSTAT3; +} + +static inline void __iomem *gpio_ns9360_gctrladdr(unsigned gpio) +{ + if (gpio < 32) + return NS9360_BBU_GCTRL1; + else if (gpio < 64) + return NS9360_BBU_GCTRL2; + else + return NS9360_BBU_GCTRL3; +} + +static inline void __iomem *gpio_ns9360_gconfaddr(unsigned gpio) +{ + if (gpio < 56) + return NS9360_BBU_GCONFb1(gpio / 8); + else + /* this could be optimised away on + * ns9750 only builds, but it isn't ... + */ + return NS9360_BBU_GCONFb2((gpio - 56) / 8); +} + +static inline int gpio_issocgpio_ns9360(unsigned gpio) +{ + return gpio <= 72; +} + +const struct gpio_to_irq_map *gpio_get_map_ns9360(unsigned gpio) __attribute__((const)); + +static inline void gpio_configure_ns9360_unlocked(unsigned gpio, + int dir, int inv, int func) +{ + void __iomem *conf = gpio_ns9360_gconfaddr(gpio); + u32 confval; + + confval = __raw_readl(conf); + REGSETIM_IDX(confval, NS9360_BBU_GCONFx, DIR, gpio & 7, dir); + REGSETIM_IDX(confval, NS9360_BBU_GCONFx, INV, gpio & 7, inv); + REGSETIM_IDX(confval, NS9360_BBU_GCONFx, FUNC, gpio & 7, func); + __raw_writel(confval, conf); +} + +static inline void gpio_configure_ns9360(unsigned gpio, + int dir, int inv, int func) +{ + unsigned long flags; + + local_irq_save(flags); + + gpio_configure_ns9360_unlocked(gpio, dir, inv, func); + + local_irq_restore(flags); +} + +static inline int gpio_get_value_ns9360(unsigned gpio) +{ + void __iomem *stat = gpio_ns9360_gstataddr(gpio); + + return (__raw_readl(stat) >> (gpio & 31)) & 1; +} + +static inline void gpio_set_value_ns9360_unlocked(unsigned gpio, int value) +{ + void __iomem *ctrl = gpio_ns9360_gctrladdr(gpio); + u32 ctrlval; + + ctrlval = __raw_readl(ctrl); + + if (value) + ctrlval |= 1 << (gpio & 31); + else + ctrlval &= ~(1 << (gpio & 31)); + + __raw_writel(ctrlval, ctrl); +} + +static inline int gpio_direction_input_ns9360_unlocked(unsigned gpio) +{ + gpio_configure_ns9360_unlocked(gpio, 0, 0, 3); + return 0; +} + +static inline int gpio_direction_irqinput_ns9360_unlocked(unsigned gpio) +{ + const struct gpio_to_irq_map *map = gpio_get_map_ns9360(gpio); + if (map) { + gpio_configure_ns9360_unlocked(gpio, 0, 0, map->func); + return 0; + } else + return gpio_direction_input_ns9360_unlocked(gpio); +} + +static inline int gpio_direction_output_ns9360_unlocked(unsigned gpio, + int value) +{ + gpio_set_value_ns9360_unlocked(gpio, value); + gpio_configure_ns9360_unlocked(gpio, 1, 0, 3); + return 0; +} + +#endif /* if defined(CONFIG_PROCESSOR_NS9360) */ + +static inline int gpio_issocgpio(unsigned gpio) +{ +#if defined(CONFIG_PROCESSOR_NS9210) + if (processor_is_ns9210()) + return gpio_issocgpio_ns9210(gpio); + else +#endif +#if defined(CONFIG_PROCESSOR_NS9215) + if (processor_is_ns9215()) + return gpio_issocgpio_ns9215(gpio); + else +#endif +#if defined(CONFIG_PROCESSOR_NS9360) + if (processor_is_ns9360()) + return gpio_issocgpio_ns9360(gpio); + else +#endif + BUG(); + + BUG(); + + return 0; +} + +#if defined(CONFIG_GPIOLIB) + +#include <asm-generic/gpio.h> + +static inline int gpio_get_value(unsigned gpio) +{ + return __gpio_get_value(gpio); +} + +static inline void gpio_set_value(unsigned gpio, int value) +{ + return __gpio_set_value(gpio, value); +} + +static inline int gpio_cansleep(unsigned gpio) +{ + return __gpio_cansleep(gpio); +} + +#else /* if defined(CONFIG_GPIOLIB) */ + +extern spinlock_t gpio_lock; + +int gpio_request(unsigned gpio, const char *label); void gpio_free(unsigned gpio); -int ns9xxx_gpio_configure(unsigned gpio, int inv, int func); +static inline int gpio_get_value(unsigned gpio) +{ +#if defined(CONFIG_PROCESSOR_NS921X) + if (processor_is_ns921x()) + return gpio_get_value_ns921x(gpio); + else +#endif +#if defined(CONFIG_PROCESSOR_NS9360) + if (processor_is_ns9360()) + return gpio_get_value_ns9360(gpio); + else +#endif + BUG(); +} + +static inline void gpio_set_value_unlocked(unsigned gpio, int value) +{ +#if defined(CONFIG_PROCESSOR_NS921X) + if (processor_is_ns921x()) + gpio_set_value_ns921x_unlocked(gpio, value); + else +#endif +#if defined(CONFIG_PROCESSOR_NS9360) + if (processor_is_ns9360()) + gpio_set_value_ns9360_unlocked(gpio, value); + else +#endif + BUG(); +} + +static inline void gpio_set_value(unsigned gpio, int value) +{ + unsigned long flags; + + BUG_ON(!gpio_issocgpio(gpio)); + + spin_lock_irqsave(&gpio_lock, flags); + + gpio_set_value_unlocked(gpio, value); + + spin_unlock_irqrestore(&gpio_lock, flags); +} + +static inline int gpio_direction_input(unsigned gpio) +{ + if (likely(gpio_issocgpio(gpio))) { + int ret = -EINVAL; + unsigned long flags; + + spin_lock_irqsave(&gpio_lock, flags); + +#if defined(CONFIG_PROCESSOR_NS921X) + if (processor_is_ns921x()) + ret = gpio_direction_irqinput_ns921x_unlocked(gpio); + else +#endif +#if defined(CONFIG_PROCESSOR_NS9360) + if (processor_is_ns9360()) + ret = gpio_direction_irqinput_ns9360_unlocked(gpio); + else +#endif + BUG(); + + spin_unlock_irqrestore(&gpio_lock, flags); -int gpio_direction_input(unsigned gpio); + return ret; + } else + return -EINVAL; +} + +static inline int gpio_direction_output(unsigned gpio, int value) +{ + if (likely(gpio_issocgpio(gpio))) { + int ret = -EINVAL; + unsigned long flags; -int gpio_direction_output(unsigned gpio, int value); + spin_lock_irqsave(&gpio_lock, flags); -int gpio_get_value(unsigned gpio); +#if defined(CONFIG_PROCESSOR_NS921X) + if (processor_is_ns921x()) + ret = gpio_direction_output_ns921x_unlocked(gpio, + value); + else +#endif +#if defined(CONFIG_PROCESSOR_NS9360) + if (processor_is_ns9360()) + ret = gpio_direction_output_ns9360_unlocked(gpio, + value); + else +#endif + BUG(); + + spin_unlock_irqrestore(&gpio_lock, flags); + + return ret; + } else + return -EINVAL; +} + +#include <asm-generic/gpio.h> + +#endif /* if defined(CONFIG_GPIOLIB) / else */ -void gpio_set_value(unsigned gpio, int value); /* * ns9xxx can use gpio pins to trigger an irq, but it's not generic @@ -33,6 +469,23 @@ void gpio_set_value(unsigned gpio, int value); */ static inline int gpio_to_irq(unsigned gpio) { +#if defined(CONFIG_PROCESSOR_NS921X) + if (processor_is_ns921x()) { + const struct gpio_to_irq_map *map = gpio_get_map_ns921x(gpio); + + if (map) + return map->irq; + } +#endif +#if defined(CONFIG_PROCESSOR_NS9360) + if (processor_is_ns9360()) { + const struct gpio_to_irq_map *map = gpio_get_map_ns9360(gpio); + + if (map) + return map->irq; + } +#endif + return -EINVAL; } @@ -41,7 +494,4 @@ static inline int irq_to_gpio(unsigned irq) return -EINVAL; } -/* get the cansleep() stubs */ -#include <asm-generic/gpio.h> - #endif /* ifndef __ASM_ARCH_GPIO_H */ diff --git a/arch/arm/mach-ns9xxx/include/mach/hardware.h b/arch/arm/mach-ns9xxx/include/mach/hardware.h index 6dbb2030f563..46299b18433e 100644 --- a/arch/arm/mach-ns9xxx/include/mach/hardware.h +++ b/arch/arm/mach-ns9xxx/include/mach/hardware.h @@ -1,7 +1,7 @@ /* * arch/arm/mach-ns9xxx/include/mach/hardware.h * - * Copyright (C) 2006 by Digi International Inc. + * Copyright (C) 2006-2008 by Digi International Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify it @@ -30,7 +30,9 @@ #define __REGSHIFT(mask) ((mask) & (-(mask))) #define __REGBIT(bit) ((u32)1 << (bit)) +#define __REGBIT_SHIFT(bit, shift) ((u32)1 << ((bit) + (shift))) #define __REGBITS(hbit, lbit) ((((u32)1 << ((hbit) - (lbit) + 1)) - 1) << (lbit)) +#define __REGBITS_SHIFT(hbit, lbit, shift) __REGBITS((hbit) + (shift), (lbit) + (shift)) #define __REGVAL(mask, value) (((value) * __REGSHIFT(mask)) & (mask)) #ifndef __ASSEMBLY__ @@ -66,13 +68,13 @@ __REGGET(var, reg ## _ ## field) / __REGSHIFT(reg ## _ ## field) # define REGGETIM_IDX(var, reg, field, idx) \ - __REGGET(var, reg ## _ ## field((idx))) / \ + __REGGET(var, reg ## _ ## field((idx))) / \ __REGSHIFT(reg ## _ ## field((idx))) #else # define __REG(x) io_p2v(x) -# define __REG2(x, y) io_p2v((x) + 4 * (y)) +# define __REG2(x, y) io_p2v((x) + (y)) #endif diff --git a/arch/arm/mach-ns9xxx/include/mach/irqs.h b/arch/arm/mach-ns9xxx/include/mach/irqs.h index 13483949e210..f72bd08e5de9 100644 --- a/arch/arm/mach-ns9xxx/include/mach/irqs.h +++ b/arch/arm/mach-ns9xxx/include/mach/irqs.h @@ -1,7 +1,7 @@ /* * arch/arm/mach-ns9xxx/include/mach/irqs.h * - * Copyright (C) 2006,2007 by Digi International Inc. + * Copyright (C) 2006-2008 by Digi International Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify it @@ -11,14 +11,48 @@ #ifndef __ASM_ARCH_IRQS_H #define __ASM_ARCH_IRQS_H -/* NetSilicon 9360 */ +/* Digi ns921x */ #define IRQ_NS9XXX_WATCHDOG 0 #define IRQ_NS9XXX_AHBBUSERR 1 -#define IRQ_NS9360_BBUSAGG 2 -/* irq 3 is reserved for NS9360 */ +#define IRQ_NS921X_EXTDMA 2 +#define IRQ_NS921X_CPUWAKE 3 #define IRQ_NS9XXX_ETHRX 4 #define IRQ_NS9XXX_ETHTX 5 -#define IRQ_NS9XXX_ETHPHY 6 +#define IRQ_NS9XXX_ETHPHY 6 /* reserved for ns9210 */ +#define IRQ_NS921X_UARTA 7 +#define IRQ_NS921X_UARTB 8 +#define IRQ_NS921X_UARTC 9 +#define IRQ_NS921X_UARTD 10 +#define IRQ_NS921X_SPI 11 +#define IRQ_NS921X_PIC0 12 +#define IRQ_NS921X_PIC1 13 +#define IRQ_NS9215_ADC 14 +#define IRQ_NS9215_EPL 15 +#define IRQ_NS921X_I2C 16 +#define IRQ_NS9215_RTC 17 +#define IRQ_NS921X_TIMER0 18 +#define IRQ_NS921X_TIMER1 19 +#define IRQ_NS921X_TIMER2 20 +#define IRQ_NS921X_TIMER3 21 +#define IRQ_NS921X_TIMER4 22 +#define IRQ_NS921X_TIMER5 23 +#define IRQ_NS921X_TIMER6 24 +#define IRQ_NS921X_TIMER7 25 +#define IRQ_NS921X_TIMER8 26 +#define IRQ_NS921X_TIMER9 27 +#define IRQ_NS9XXX_EXT0 28 +#define IRQ_NS9XXX_EXT1 29 +#define IRQ_NS9XXX_EXT2 30 +#define IRQ_NS9XXX_EXT3 31 + +/* NetSilicon 9360 */ +/* IRQ_NS9XXX_WATCHDOG 0 */ +/* IRQ_NS9XXX_AHBBUSERR 1 */ +#define IRQ_NS9360_BBUSAGG 2 +/* irq 3 is reserved for NS9360 */ +/* IRQ_NS9XXX_ETHRX 3 */ +/* IRQ_NS9XXX_ETHTX 4 */ +/* IRQ_NS9XXX_ETHPHY 5 */ #define IRQ_NS9360_LCD 7 #define IRQ_NS9360_SERBRX 8 #define IRQ_NS9360_SERBTX 9 @@ -40,37 +74,39 @@ #define IRQ_NS9360_USBHOST 25 #define IRQ_NS9360_USBDEVICE 26 #define IRQ_NS9360_IEEE1284 27 -#define IRQ_NS9XXX_EXT0 28 -#define IRQ_NS9XXX_EXT1 29 -#define IRQ_NS9XXX_EXT2 30 -#define IRQ_NS9XXX_EXT3 31 +/* IRQ_NS9XXX_EXT0 28 */ +/* IRQ_NS9XXX_EXT1 29 */ +/* IRQ_NS9XXX_EXT2 30 */ +/* IRQ_NS9XXX_EXT3 31 */ + +#define IRQ_NS9360_BBUS(irq) (32 + irq) -#define BBUS_IRQ(irq) (32 + irq) +#define IRQ_NS9360_BBUS_DMA IRQ_NS9360_BBUS(0) +#define IRQ_NS9360_BBUS_SERBRX IRQ_NS9360_BBUS(2) +#define IRQ_NS9360_BBUS_SERBTX IRQ_NS9360_BBUS(3) +#define IRQ_NS9360_BBUS_SERARX IRQ_NS9360_BBUS(4) +#define IRQ_NS9360_BBUS_SERATX IRQ_NS9360_BBUS(5) +#define IRQ_NS9360_BBUS_SERCRX IRQ_NS9360_BBUS(6) +#define IRQ_NS9360_BBUS_SERCTX IRQ_NS9360_BBUS(7) +#define IRQ_NS9360_BBUS_SERDRX IRQ_NS9360_BBUS(8) +#define IRQ_NS9360_BBUS_SERDTX IRQ_NS9360_BBUS(9) +#define IRQ_NS9360_BBUS_I2C IRQ_NS9360_BBUS(10) +#define IRQ_NS9360_BBUS_1284 IRQ_NS9360_BBUS(11) +#define IRQ_NS9360_BBUS_UTIL IRQ_NS9360_BBUS(12) +#define IRQ_NS9360_BBUS_RTC IRQ_NS9360_BBUS(13) +#define IRQ_NS9360_BBUS_USBHST IRQ_NS9360_BBUS(14) +#define IRQ_NS9360_BBUS_USBDEV IRQ_NS9360_BBUS(15) +#define IRQ_NS9360_BBUS_AHBDMA1 IRQ_NS9360_BBUS(24) +#define IRQ_NS9360_BBUS_AHBDMA2 IRQ_NS9360_BBUS(25) -#define IRQ_BBUS_DMA BBUS_IRQ(0) -#define IRQ_BBUS_SERBRX BBUS_IRQ(2) -#define IRQ_BBUS_SERBTX BBUS_IRQ(3) -#define IRQ_BBUS_SERARX BBUS_IRQ(4) -#define IRQ_BBUS_SERATX BBUS_IRQ(5) -#define IRQ_BBUS_SERCRX BBUS_IRQ(6) -#define IRQ_BBUS_SERCTX BBUS_IRQ(7) -#define IRQ_BBUS_SERDRX BBUS_IRQ(8) -#define IRQ_BBUS_SERDTX BBUS_IRQ(9) -#define IRQ_BBUS_I2C BBUS_IRQ(10) -#define IRQ_BBUS_1284 BBUS_IRQ(11) -#define IRQ_BBUS_UTIL BBUS_IRQ(12) -#define IRQ_BBUS_RTC BBUS_IRQ(13) -#define IRQ_BBUS_USBHST BBUS_IRQ(14) -#define IRQ_BBUS_USBDEV BBUS_IRQ(15) -#define IRQ_BBUS_AHBDMA1 BBUS_IRQ(24) -#define IRQ_BBUS_AHBDMA2 BBUS_IRQ(25) +#define IRQ_NS9360_BBUDMA(irq) (58 + irq) /* * these Interrupts are specific for the a9m9750dev board. * They are generated by an FPGA that interrupts the CPU on * IRQ_NS9360_EXT2 */ -#define FPGA_IRQ(irq) (64 + irq) +#define FPGA_IRQ(irq) (74 + irq) #define IRQ_FPGA_UARTA FPGA_IRQ(0) #define IRQ_FPGA_UARTB FPGA_IRQ(1) @@ -81,6 +117,6 @@ #define IRQ_FPGA_CAN0 FPGA_IRQ(6) #define IRQ_FPGA_CAN1 FPGA_IRQ(7) -#define NR_IRQS 72 +#define NR_IRQS 82 #endif /* __ASM_ARCH_IRQS_H */ diff --git a/arch/arm/mach-ns9xxx/include/mach/module.h b/arch/arm/mach-ns9xxx/include/mach/module.h index f851a6b7da6c..6c497bf87084 100644 --- a/arch/arm/mach-ns9xxx/include/mach/module.h +++ b/arch/arm/mach-ns9xxx/include/mach/module.h @@ -31,6 +31,11 @@ || machine_is_cc9p9215js() \ ) +#define module_is_ccw9p9215() (0 \ + || machine_is_ccw9p9215() \ + || machine_is_ccw9p9215js() \ + ) + #define module_is_cc9p9360() (0 \ || machine_is_a9m9360() \ || machine_is_cc9p9360dev() \ @@ -49,6 +54,11 @@ || machine_is_ccw9c() \ ) +#define module_is_cme9210() (0 \ + || machine_is_cme9210() \ + || machine_is_cme9210js() \ + ) + #define module_is_inc20otter() (0 \ || machine_is_inc20otter() \ ) diff --git a/arch/arm/mach-ns9xxx/include/mach/ns921x-serial.h b/arch/arm/mach-ns9xxx/include/mach/ns921x-serial.h new file mode 100644 index 000000000000..e879492fe10a --- /dev/null +++ b/arch/arm/mach-ns9xxx/include/mach/ns921x-serial.h @@ -0,0 +1,22 @@ +/* + * include/linux/ns9360.h + * + * 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. + */ + +#ifndef __NS921X_SERIAL_H__ +#define __NS921X_SERIAL_H__ + + +struct ns921x_uart_data { + unsigned int gpios[8]; + unsigned int nr_gpios; + unsigned int rtsen; /* RTS for 485 transceiver control */ +}; + +#endif diff --git a/arch/arm/mach-ns9xxx/include/mach/ns9360fb.h b/arch/arm/mach-ns9xxx/include/mach/ns9360fb.h new file mode 100644 index 000000000000..cacb56c17997 --- /dev/null +++ b/arch/arm/mach-ns9xxx/include/mach/ns9360fb.h @@ -0,0 +1,26 @@ +#ifndef __NS9360FB_H__ +#define __NS9360FB_H__ + + +struct ns9360fb_display { + + /* Display name */ + char *display_name; + + unsigned height; + unsigned width; + unsigned clock; + + u32 timing[4]; + u32 control; + + void (*display_power_enable)(int); +}; + +struct ns9360fb_pdata { + unsigned num_displays; /* number of defined displays */ + struct ns9360fb_display *displays; /* attached diplays info */ + struct ns9360fb_display *display; /* attached diplays info */ +}; + +#endif diff --git a/arch/arm/mach-ns9xxx/include/mach/ns9xxx-pwm.h b/arch/arm/mach-ns9xxx/include/mach/ns9xxx-pwm.h new file mode 100644 index 000000000000..b48527482cd3 --- /dev/null +++ b/arch/arm/mach-ns9xxx/include/mach/ns9xxx-pwm.h @@ -0,0 +1,146 @@ +/* + * drivers/pwm/ns9xxx-pwm.h + * + * Copyright (C) 2009 Digi International Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __NS9XXX_PWM_HEADER_H +#define __NS9XXX_PWM_HEADER_H + +/* Maximal number of available channels */ +#define NS9XXX_PWM_CHANNEL_MAX 10 + +/* This is the data for the PWM channels */ +struct ns9xxx_pwm_channel { + int timer; + int gpio; + + /* Additional channel configuration variables ... */ +}; + +/* */ +struct ns9xxx_pwm_pdata { + unsigned int number_channels; + struct ns9xxx_pwm_channel *channels; +}; + + + + +#define NS921X_TMC_T0E (1 << 0) /* Timer enable */ +#define NS921X_TMC_T1E (1 << 1) +#define NS921X_TMC_T2E (1 << 2) +#define NS921X_TMC_T3E (1 << 3) +#define NS921X_TMC_T4E (1 << 4) +#define NS921X_TMC_T5E (1 << 5) +#define NS921X_TMC_T6E (1 << 6) +#define NS921X_TMC_T7E (1 << 7) +#define NS921X_TMC_T8E (1 << 8) +#define NS921X_TMC_T9E (1 << 9) +#define NS921X_TMC_T6HSE (1 << 10) /* High step enable */ +#define NS921X_TMC_T6LSE (1 << 11) /* Low step enable */ +#define NS921X_TMC_T6RSE (1 << 12) /* Reload step enable */ +#define NS921X_TMC_T7HSE (1 << 13) +#define NS921X_TMC_T7LSE (1 << 14) +#define NS921X_TMC_T7RSE (1 << 15) +#define NS921X_TMC_T8HSE (1 << 16) +#define NS921X_TMC_T8LSE (1 << 17) +#define NS921X_TMC_T8RSE (1 << 18) +#define NS921X_TMC_T9HSE (1 << 19) +#define NS921X_TMC_T9LSE (1 << 20) +#define NS921X_TMC_T9RSE (1 << 21) + +#define NS921X_TCR_RELOADEN (1 << 0) /* Reload enable */ +#define NS921X_TCR_BITTIMER (1 << 1) /* 32 or 16 bit timer */ +#define NS921X_TCR_UPDOWN (1 << 2) /* Up/Down select */ +#define NS921X_TCR_INTSEL (1 << 3) /* Interrupt select */ + +#define NS921X_TCR_TMODE(x) ((x) & (0x3 << 4)) /* Timer mode */ +#define NS921X_TCR_TMODE_MASK (0x3 << 4) +#define NS921X_TCR_TMODE_INT (0 << 4) +#define NS921X_TCR_TMODE_EXTLOW (1 << 4) +#define NS921X_TCR_TMODE_EXTHIGH (2 << 4) +/* @TODO: Complete the remaining macros */ +//#define NS921X_TCR_TMODE (2 << 4) /* Timer mode */ + +#define NS921X_TCR_TCLKSEL (0xf << 6) /* Timer clock set */ +#define NS921X_TCR_TCLKSEL_MASK (0xf << 6) +#define NS921X_TCR_TCLKSEL_AHB (0x1 << 6) +#define NS921X_TCR_INTCLR (1 << 10) /* Interrupt clear */ +#define NS921X_TCR_DEBUGMODE (1 << 11) /* Debug mode */ +#define NS921X_TCR_CAPCOMP (7 << 12) /* Capture and compare mode functions */ +#define NS921X_TCR_TE (1 << 15) /* Timer enable */ +#define NS921X_TCR_TMODE2 (3 << 16) /* Timer mode 2 */ +#define NS921X_TCR_TMODE2_PWM (1 << 16) /* Timer mode 2 */ + +#define NS921X_TCR_RELOADMODE2 (1 << 18) /* Reload mode */ + +#define NS921X_THIGHREG (32 << 0) /* PWM output toggles high when timer counter reaches this value */ +#define NS921X_TLOWREG (32 << 0) /* PWM toggles low when counter reaches this value */ + +#define NS921X_HISTEP_DIR (1 << 31) /* High step direction */ +#define NS921X_HISTEP (15 << 16) /* High step */ +#define NS921X_LOWSTEP_DIR (1 << 15) /* Low step direction */ +#define NS921X_LOWSTEP (15 << 0) /* Low step */ + +#define NS921X_RELOADSTEPDIR (1 << 15) /* Reload step direction */ +#define NS921X_RELOADSTEP (15 << 0) /* Reload step */ + +#define NS921X_TIMECOMP (16 << 16) /* Timer compare register or timer reload bits 31:16 count register */ +#define NS921X_TIMERELOADBITS (16 << 0) /* Timer reload bits 15:00 count register */ + +#define NS921X_TIMERCAP (16 << 16) /* Timer capture register or timer read bits 31:16 register */ +#define NS921X_TIMERREAD (16 << 0) /* Timer read bits 15:00 register */ + + + +#if 0 +struct pwm_channel { + void __iomem *regs; + unsigned index; + unsigned long mck; +}; + +extern int pwm_channel_alloc(int index, struct pwm_channel *ch); +extern int pwm_channel_free(struct pwm_channel *ch); + +extern int pwm_clk_alloc(unsigned prescale, unsigned div); +extern void pwm_clk_free(unsigned clk); + +extern int __pwm_channel_onoff(struct pwm_channel *ch, int enabled); + +#define pwm_channel_enable(ch) __pwm_channel_onoff((ch), 1) +#define pwm_channel_disable(ch) __pwm_channel_onoff((ch), 0) + +/* periodic interrupts, mostly for CUPD changes to period or cycle */ +extern int pwm_channel_handler(struct pwm_channel *ch, + void (*handler)(struct pwm_channel *ch)); + +static inline void +pwm_channel_writel(struct pwm_channel *pwmc, unsigned offset, u32 val) +{ + __raw_writel(val, pwmc->regs + offset); +} + +static inline u32 pwm_channel_readl(struct pwm_channel *pwmc, unsigned offset) +{ + return __raw_readl(pwmc->regs + offset); +} + +#endif /* __LINUX_NS9XXX_PWM_H */ + +#endif /* __NS9XXX_PWM_HEADER_H */ diff --git a/arch/arm/mach-ns9xxx/include/mach/processor.h b/arch/arm/mach-ns9xxx/include/mach/processor.h index 9f77f746a386..a36ce171b4e3 100644 --- a/arch/arm/mach-ns9xxx/include/mach/processor.h +++ b/arch/arm/mach-ns9xxx/include/mach/processor.h @@ -16,12 +16,14 @@ #define processor_is_ns9210() (0 \ || module_is_cc7ucamry() \ || module_is_cc9p9210() \ + || module_is_cme9210() \ || module_is_inc20otter() \ || module_is_otter() \ ) #define processor_is_ns9215() (0 \ || module_is_cc9p9215() \ + || module_is_ccw9p9215() \ ) #define processor_is_ns9360() (0 \ diff --git a/arch/arm/mach-ns9xxx/include/mach/regs-bbu.h b/arch/arm/mach-ns9xxx/include/mach/regs-bbu.h index af227c058fb9..564498990063 100644 --- a/arch/arm/mach-ns9xxx/include/mach/regs-bbu.h +++ b/arch/arm/mach-ns9xxx/include/mach/regs-bbu.h @@ -8,38 +8,51 @@ * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. */ -#ifndef __ASM_ARCH_REGSBBU_H -#define __ASM_ARCH_REGSBBU_H +#ifndef __ASM_ARCH_REGS_BBU_H +#define __ASM_ARCH_REGS_BBU_H #include <mach/hardware.h> /* BBus Utility */ +#define NS9360_BBU_MSR __REG(0x90600000) + /* GPIO Configuration Registers block 1 */ /* NOTE: the HRM starts counting at 1 for the GPIO registers, here the start is - * at 0 for each block. That is, BBU_GCONFb1(0) is GPIO Configuration Register - * #1, BBU_GCONFb2(0) is GPIO Configuration Register #8. */ -#define BBU_GCONFb1(x) __REG2(0x90600010, (x)) -#define BBU_GCONFb2(x) __REG2(0x90600100, (x)) - -#define BBU_GCONFx_DIR(m) __REGBIT(3 + (((m) & 7) << 2)) -#define BBU_GCONFx_DIR_INPUT(m) __REGVAL(BBU_GCONFx_DIR(m), 0) -#define BBU_GCONFx_DIR_OUTPUT(m) __REGVAL(BBU_GCONFx_DIR(m), 1) -#define BBU_GCONFx_INV(m) __REGBIT(2 + (((m) & 7) << 2)) -#define BBU_GCONFx_INV_NO(m) __REGVAL(BBU_GCONFx_INV(m), 0) -#define BBU_GCONFx_INV_YES(m) __REGVAL(BBU_GCONFx_INV(m), 1) -#define BBU_GCONFx_FUNC(m) __REGBITS(1 + (((m) & 7) << 2), ((m) & 7) << 2) -#define BBU_GCONFx_FUNC_0(m) __REGVAL(BBU_GCONFx_FUNC(m), 0) -#define BBU_GCONFx_FUNC_1(m) __REGVAL(BBU_GCONFx_FUNC(m), 1) -#define BBU_GCONFx_FUNC_2(m) __REGVAL(BBU_GCONFx_FUNC(m), 2) -#define BBU_GCONFx_FUNC_3(m) __REGVAL(BBU_GCONFx_FUNC(m), 3) - -#define BBU_GCTRL1 __REG(0x90600030) -#define BBU_GCTRL2 __REG(0x90600034) -#define BBU_GCTRL3 __REG(0x90600120) - -#define BBU_GSTAT1 __REG(0x90600040) -#define BBU_GSTAT2 __REG(0x90600044) -#define BBU_GSTAT3 __REG(0x90600130) - -#endif /* ifndef __ASM_ARCH_REGSBBU_H */ + * at 0 for each block. That is, NS9360_BBU_GCONFb1(0) is GPIO Configuration + * Register #1, NS9360_BBU_GCONFb2(0) is GPIO Configuration Register #8. */ +#define NS9360_BBU_GCONFb1(x) __REG2(0x90600010, (x)) +#define NS9360_BBU_GCONFb2(x) __REG2(0x90600100, (x)) + +#define __NS9360_BBU_GCONFx_SHIFT(m) (((m) & 7) << 2) + +#define NS9360_BBU_GCONFx_DIR(m) __REGBIT_SHIFT(3, __NS9360_BBU_GCONFx_SHIFT(m)) +#define NS9360_BBU_GCONFx_DIR_INPUT(m) __REGVAL(NS9360_BBU_GCONFx_DIR(m), 0) +#define NS9360_BBU_GCONFx_DIR_OUTPUT(m) __REGVAL(NS9360_BBU_GCONFx_DIR(m), 1) +#define NS9360_BBU_GCONFx_INV(m) __REGBIT_SHIFT(2, __NS9360_BBU_GCONFx_SHIFT(m)) +#define NS9360_BBU_GCONFx_INV_NO(m) __REGVAL(NS9360_BBU_GCONFx_INV(m), 0) +#define NS9360_BBU_GCONFx_INV_YES(m) __REGVAL(NS9360_BBU_GCONFx_INV(m), 1) +#define NS9360_BBU_GCONFx_FUNC(m) __REGBITS_SHIFT(1, 0, __NS9360_BBU_GCONFx_SHIFT(m)) +#define NS9360_BBU_GCONFx_FUNC_0(m) __REGVAL(NS9360_BBU_GCONFx_FUNC(m), 0) +#define NS9360_BBU_GCONFx_FUNC_1(m) __REGVAL(NS9360_BBU_GCONFx_FUNC(m), 1) +#define NS9360_BBU_GCONFx_FUNC_2(m) __REGVAL(NS9360_BBU_GCONFx_FUNC(m), 2) +#define NS9360_BBU_GCONFx_FUNC_3(m) __REGVAL(NS9360_BBU_GCONFx_FUNC(m), 3) + +#define NS9360_BBU_GCTRL1 __REG(0x90600030) +#define NS9360_BBU_GCTRL2 __REG(0x90600034) +#define NS9360_BBU_GCTRL3 __REG(0x90600120) + +#define NS9360_BBU_GSTAT1 __REG(0x90600040) +#define NS9360_BBU_GSTAT2 __REG(0x90600044) +#define NS9360_BBU_GSTAT3 __REG(0x90600130) + +#define NS9360_BBUS_USB __REG(0x90600070) + +#define NS9360_BBUS_DMA_ISTAT __REG(0x90600060) +#define NS9360_BBUS_DMA_IEN __REG(0x90600064) + +#define NS9360_BBUS_ISTAT __REG(0xa0401000) +#define NS9360_BBUS_IEN __REG(0xa0401004) +#define NS9360_BBUS_IEN_GLBL (1 << 31) + +#endif /* ifndef __ASM_ARCH_REGS_BBU_H */ diff --git a/arch/arm/mach-ns9xxx/include/mach/regs-io-ns921x.h b/arch/arm/mach-ns9xxx/include/mach/regs-io-ns921x.h new file mode 100644 index 000000000000..948a273a9621 --- /dev/null +++ b/arch/arm/mach-ns9xxx/include/mach/regs-io-ns921x.h @@ -0,0 +1,41 @@ +/* + * arch/arm/mach-ns9xxx/include/mach/regs-io-ns921x.h + * + * Copyright (C) 2007-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. + */ +#ifndef __ASM_ARCH_REGSIONS921X_H +#define __ASM_ARCH_REGSIONS921X_H + +#include <mach/hardware.h> + +#define __NS921X_IO_GPIOCONF_SHIFT(m) (((m) & 3) << 3) + +/* I/O Control Module */ + +/* NOTE: the first GPIO has number #0, this is different from NS9360 which + * starts at #1 */ + +/* GPIO Configuration Register */ +#define NS921X_IO_GPIOCONFx(x) __REG2(0xa0902000, (x)) + +#define NS921X_IO_GPIOCONFx_FUNC(m) __REGBITS_SHIFT(5, 3, __NS921X_IO_GPIOCONF_SHIFT(m)) +#define NS921X_IO_GPIOCONFx_DIR(m) __REGBIT(2 + __NS921X_IO_GPIOCONF_SHIFT(m)) +#define NS921X_IO_GPIOCONFx_DIR_IN(m) __REGVAL(NS921X_IO_GPIOCONF_DIR(m), 0) +#define NS921X_IO_GPIOCONFx_DIR_OUT(m) __REGVAL(NS921X_IO_GPIOCONF_DIR(m), 1) +#define NS921X_IO_GPIOCONFx_INV(m) __REGBIT(1 + __NS921X_IO_GPIOCONF_SHIFT(m)) +#define NS921X_IO_GPIOCONFx_INV_OFF(m) __REGVAL(NS921X_IO_GPIOCONF_INV(m), 0) +#define NS921X_IO_GPIOCONFx_INV_ON(m) __REGVAL(NS921X_IO_GPIOCONF_INV(m), 1) +#define NS921X_IO_GPIOCONFx_PUEN(m) __REGBIT(__NS921X_IO_GPIOCONF_SHIFT(m)) +#define NS921X_IO_GPIOCONFx_PUEN_EN(m) __REGVAL(NS921X_IO_GPIOCONF_PUEN(m), 0) +#define NS921X_IO_GPIOCONFx_PUEN_DIS(m) __REGVAL(NS921X_IO_GPIOCONF_PUEN(m), 1) + +#define NS921X_IO_GPIOCTRLx(x) __REG2(0xa090206c, (x)) + +#define NS921X_IO_GPIOSTATx(x) __REG2(0xa090207c, (x)) + +#endif /* ifndef __ASM_ARCH_REGSSYSNS921X_H */ diff --git a/arch/arm/mach-ns9xxx/include/mach/regs-iohub-ns921x.h b/arch/arm/mach-ns9xxx/include/mach/regs-iohub-ns921x.h new file mode 100644 index 000000000000..8b274bb8bcd8 --- /dev/null +++ b/arch/arm/mach-ns9xxx/include/mach/regs-iohub-ns921x.h @@ -0,0 +1,133 @@ +/*
+ * arch/arm/mach-ns9xxx/include/mach/regs-sys-ns921x.h
+ *
+ * Copyright (C) 2007 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.
+ *
+ * !Revision: $Revision: 1.0 $
+ * !Author: Luis Galdos
+ * !Desc:
+ * !References:
+ */
+
+#ifndef __ASM_ARCH_REGSIOHUB_NS921X_H
+#define __ASM_ARCH_REGSIOHUB_NS921X_H
+
+#include <mach/hardware.h>
+#include <mach/regs-sys-common.h>
+
+#define IOHUB_REG_BASE_PA (0x90000000)
+#define IOHUB_REG_BASE_VA io_p2v(IOHUB_REG_BASE_PA)
+#define IOHUB_REG_OFFSET (0x8000)
+#define IOHUB_FIM0_BASE_PA IOHUB_REG_BASE_PA
+#define IOHUB_FIM1_BASE_PA (IOHUB_REG_BASE_PA + IOHUB_REG_OFFSET)
+#define IOHUB_FIM0_BASE_VA io_p2v(IOHUB_FIM0_BASE_PA)
+#define IOHUB_FIM1_BASE_VA io_p2v(IOHUB_FIM1_BASE_PA)
+
+/* Register offsets for the IOHUB-components */
+#define IOHUB_IFS_REG (0x00)
+
+#define IOHUB_RX_DMA_CTRL_REG (0x04)
+#define IOHUB_RX_DMA_BUFPTR_REG (0x08)
+#define IOHUB_RX_DMA_ICTRL_REG (0x0C)
+#define IOHUB_RX_DIR_REG (0x10)
+#define IOHUB_RX_DIR_FIFO_REG (0x14)
+#define IOHUB_TX_DMA_CTRL_REG (0x18)
+#define IOHUB_TX_DMA_BUFPTR_REG (0x1C)
+#define IOHUB_TX_ICTRL_REG (0x20)
+#define IOHUB_TX_FIFO_REG (0x28)
+#define IOHUB_TX_DIR_REG (0x2C)
+
+/* DMA RX control bits */
+#define IOHUB_RX_DMA_CTRL_CE (1<<31)
+#define IOHUB_RX_DMA_CTRL_CA (1<<30)
+#define IOHUB_RX_DMA_CTRL_FLEXIO (1<<29)
+#define IOHUB_RX_DMA_CTRL_DIRECT (1<<28)
+#define IOHUB_RX_DMA_CTRL_STATE (0xFC00)
+#define IOHUB_RX_DMA_CTRL_INDEX (0x03FF)
+
+
+/* DMA TX control bits */
+#define IOHUB_TX_DMA_CTRL_CE (1<<31)
+#define IOHUB_TX_DMA_CTRL_CA (1<<30)
+#define IOHUB_TX_DMA_CTRL_FLEXIO (1<<29)
+#define IOHUB_TX_DMA_CTRL_DIRECT (1<<28)
+#define IOHUB_TX_DMA_CTRL_STATE (0xFC00)
+#define IOHUB_TX_DMA_CTRL_INDEXEN (1<<27)
+#define IOHUB_TX_DMA_CTRL_INDEX(i) (i & 0x03FF)
+
+
+
+/* Interrupt and FIFO status register */
+#define IOHUB_IFS_RXNCIP (1<<31)
+#define IOHUB_IFS_RXECIP (1<<30)
+#define IOHUB_IFS_RXNRIP (1<<29)
+#define IOHUB_IFS_RXCAIP (1<<28)
+#define IOHUB_IFS_TXNCIP (1<<24)
+#define IOHUB_IFS_TXECIP (1<<23)
+#define IOHUB_IFS_TXNRIP (1<<22)
+#define IOHUB_IFS_TXCAIP (1<<21)
+#define IOHUB_IFS_TXFUFIP (1<<20)
+#define IOHUB_IFS_TXFSRIP (1<<19)
+#define IOHUB_IFS_MODIP (1<<18)
+#define IOHUB_IFS_DMA_TX (IOHUB_IFS_TXNCIP | \
+ IOHUB_IFS_TXNRIP | \
+ IOHUB_IFS_TXECIP | \
+ IOHUB_IFS_TXCAIP)
+#define IOHUB_IFS_DMA_RX (IOHUB_IFS_RXNCIP | \
+ IOHUB_IFS_RXNRIP | \
+ IOHUB_IFS_RXECIP | \
+ IOHUB_IFS_RXCAIP)
+
+/* Interrupt configuration register */
+#define IOHUB_ICTRL_RXTHRS(val) (val<<28)
+#define IOHUB_ICTRL_RXFOFIE (1<<26)
+#define IOHUB_ICTRL_RXFSRIE (1<<25)
+#define IOHUB_ICTRL_RXNCIE (1<<24)
+#define IOHUB_ICTRL_RXECIE (1<<23)
+#define IOHUB_ICTRL_RXNRIE (1<<22)
+#define IOHUB_ICTRL_RXCAIE (1<<21)
+#define IOHUB_ICTRL_RXPCIE (1<<20)
+#define IOHUB_ICTRL_WSTAT (1<<19)
+#define IOHUB_ICTRL_ISTAT (1<<18)
+#define IOHUB_ICTRL_LSTAT (1<<17)
+#define IOHUB_ICTRL_FSTAT (1<<16)
+#define IOHUB_ICTRL_BLENSTAT (0xFF)
+#define IOHUB_ICTRL_RXALLE (IOHUB_ICTRL_RXFOFIE | \
+ IOHUB_ICTRL_RXFSRIE | \
+ IOHUB_ICTRL_RXNCIE | \
+ IOHUB_ICTRL_RXECIE | \
+ IOHUB_ICTRL_RXNRIE | \
+ IOHUB_ICTRL_RXCAIE | \
+ IOHUB_ICTRL_RXPCIE)
+
+
+#define IOHUB_ICTRL_TXTHRS(val) (val<<28)
+#define IOHUB_ICTRL_TXFUFIE (1<<26)
+#define IOHUB_ICTRL_TXFSRIE (1<<25)
+#define IOHUB_ICTRL_TXNCIE (1<<24)
+#define IOHUB_ICTRL_TXECIE (1<<23)
+#define IOHUB_ICTRL_TXNRIE (1<<22)
+#define IOHUB_ICTRL_TXCAIE (1<<21)
+#define IOHUB_ICTRL_WSTAT (1<<19)
+#define IOHUB_ICTRL_ISTAT (1<<18)
+#define IOHUB_ICTRL_LSTAT (1<<17)
+#define IOHUB_ICTRL_FSTAT (1<<16)
+#define IOHUB_ICTRL_BLENSTAT (0xFF)
+#define IOHUB_ICTRL_TXALLE (IOHUB_ICTRL_TXFUFIE | \
+ IOHUB_ICTRL_TXFSRIE | \
+ IOHUB_ICTRL_TXNCIE | \
+ IOHUB_ICTRL_TXECIE | \
+ IOHUB_ICTRL_TXNRIE | \
+ IOHUB_ICTRL_TXCAIE)
+
+
+
+#endif /* ifndef __ASM_ARCH_REGSIOHUB_NS921X_H */
+
+
+
diff --git a/arch/arm/mach-ns9xxx/include/mach/regs-lcd-ns9360.h b/arch/arm/mach-ns9xxx/include/mach/regs-lcd-ns9360.h new file mode 100644 index 000000000000..7beabc4729bc --- /dev/null +++ b/arch/arm/mach-ns9xxx/include/mach/regs-lcd-ns9360.h @@ -0,0 +1,88 @@ +/* + * arch/arm/mach-ns9xxx/include/mach/regs-lcd-ns9360.h + * + * 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. + */ + +#ifndef __ASM_ARCH_REGSLCDNS9360_H +#define __ASM_ARCH_REGSLCDNS9360_H + +#define LCD_TIMING0 0x00 +#define LCD_TIMING0_HBP(x) (((x) & 0xFF) << 24) +#define LCD_TIMING0_HFP(x) (((x) & 0xFF) << 16) +#define LCD_TIMING0_HSW(x) (((x) & 0xFF) << 8) +#define LCD_TIMING0_PPL(x) (((x) & 0x3F) << 2) + +#define LCD_TIMING1 0x04 +#define LCD_TIMING1_VBP(x) (((x) & 0xFF) << 24) +#define LCD_TIMING1_VFP(x) (((x) & 0xFF) << 16) +#define LCD_TIMING1_VSW(x) (((x) & 0x3F) << 10) +#define LCD_TIMING1_LPP(x) (((x) & 0x3FF)) + +#define LCD_TIMING2 0x08 +#define LCD_TIMING2_BCD (1 << 26) +#define LCD_TIMING2_CPL(x) (((x) & 0x3FF) << 16) +#define LCD_TIMING2_IOE (1 << 14) +#define LCD_TIMING2_IPC (1 << 13) +#define LCD_TIMING2_IHS (1 << 12) +#define LCD_TIMING2_IVS (1 << 11) +#define LCD_TIMING2_ACB(x) (((x) & 0x1F) << 6) +#define LCD_TIMING2_PCD(x) (((x) & 0x1F)) + +#define LCD_TIMING3 0x0c +#define LCD_TIMING3_LEE (1 << 16) +#define LCD_TIMING3_LED(x) (((x) & 0x7F)) + +#define LCD_UPBASE 0x10 +#define LCD_UPBASE_V(x) (((x) & 0x3FFFFFFF)<<2) + +#define LCD_LPBASE 0x14 +#define LCD_PBASE_V(x) (((x) & 0x3FFFFFFF)<<2) + +#define LCD_IRENABLE 0x18 +#define LCD_IRENABLE_MBERR (1 << 3) +#define LCD_IRENABLE_VCOMP (1 << 2) +#define LCD_IRENABLE_LNBU (1 << 1) + +#define LCD_CONTROL 0x1c +#define LCD_CONTROL_WATERMARK (1 << 16) +#define LCD_CONTROL_VCOMP_MA (3 << 12) +#define LCD_CONTROL_VCOMP_VS (0 << 12) +#define LCD_CONTROL_VCOMP_BP (1 << 12) +#define LCD_CONTROL_VCOMP_AV (2 << 12) +#define LCD_CONTROL_VCOMP_FP (3 << 12) +#define LCD_CONTROL_PWR (1 << 11) +#define LCD_CONTROL_BEPO (1 << 10) +#define LCD_CONTROL_BEBO (1 << 9) +#define LCD_CONTROL_BGR (1 << 8) +#define LCD_CONTROL_DUAL (1 << 7) +#define LCD_CONTROL_MONO8 (1 << 6) +#define LCD_CONTROL_TFT (1 << 5) +#define LCD_CONTROL_BW (1 << 4) +#define LCD_CONTROL_BPP_MA (7 << 1) +#define LCD_CONTROL_BPP_1 (0 << 1) +#define LCD_CONTROL_BPP_2 (1 << 1) +#define LCD_CONTROL_BPP_4 (2 << 1) +#define LCD_CONTROL_BPP_8 (3 << 1) +#define LCD_CONTROL_BPP_16 (4 << 1) +#define LCD_CONTROL_EN (1 << 0) + +#define LCD_STATUS 0x20 +#define LCD_STATUS_MBERROR (4 << 1) +#define LCD_STATUS_VCOMP (3 << 1) +#define LCD_STATUS_LNBU (2 << 1) + +#define LCD_INTR 0x24 +#define LCD_INTR_MBERROR (4 << 1) +#define LCD_INTR_VCOMP (3 << 1) +#define LCD_INTR_LNBUINTR (2 << 1) + +#define LCD_UPCURRENT 0x28 +#define LCD_LPCURRENT 0x2c + +#endif diff --git a/arch/arm/mach-ns9xxx/include/mach/regs-sys-common.h b/arch/arm/mach-ns9xxx/include/mach/regs-sys-common.h index 14f91dfd5736..3041d3f6f44a 100644 --- a/arch/arm/mach-ns9xxx/include/mach/regs-sys-common.h +++ b/arch/arm/mach-ns9xxx/include/mach/regs-sys-common.h @@ -1,7 +1,7 @@ /* * arch/arm/mach-ns9xxx/include/mach/regs-sys-common.h * - * Copyright (C) 2007 by Digi International Inc. + * Copyright (C) 2007,2008 by Digi International Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify it @@ -18,6 +18,12 @@ /* Interrupt Configuration registers */ #define SYS_IC(x) __REG2(0xa0900144, (x)) +#define __SYS_IC_FIELDNUM(i) (3 - ((i) & 3)) +#define __SYS_IC_SHIFT(i) (((i) & 3) << 3) +#define SYS_IC_IE(i) __REGBIT(7 + __SYS_IC_SHIFT(i)) +#define SYS_IC_IE_EN(i) __REGVAL(SYS_IC_IE(i), 1) +#define SYS_IC_IE_DIS(i) __REGVAL(SYS_IC_IE(i), 0) +#define SYS_IC_ISD(i) __REGBITS_SHIFT(4, 0, __SYS_IC_SHIFT(i)) /* ISRADDR */ #define SYS_ISRADDR __REG(0xa0900164) @@ -28,4 +34,43 @@ /* Interrupt Status Raw */ #define SYS_ISR __REG(0xa090016c) +/* Active Interrupt Level ID Status register */ +#define SYS_AILID __REG(0xa090018c) + +/* System Memory Chip Select x Dynamic Memory Base */ +#define SYS_SMCSDMB(x) __REG2(0xa09001d0, (x) << 1) + +/* System Memory Chip Select x Dynamic Memory Mask */ +#define SYS_SMCSDMM(x) __REG2(0xa09001d4, (x) << 1) + +/* System Memory Chip Select x Static Memory Base */ +#define SYS_SMCSSMB(x) __REG2(0xa09001f0, (x) << 1) + +/* System Memory Chip Select x Static Memory Base: Chip select x base */ +#define SYS_SMCSSMB_CSxB __REGBITS(31, 12) + +/* System Memory Chip Select x Static Memory Mask */ +#define SYS_SMCSSMM(x) __REG2(0xa09001f4, (x) << 1) + +/* System Memory Chip Select x Static Memory Mask: Chip select x mask */ +#define SYS_SMCSSMM_CSxM __REGBITS(31, 12) + +/* System Memory Chip Select x Static Memory Mask: Chip select x enable */ +#define SYS_SMCSSMM_CSEx __REGBIT(0) +#define SYS_SMCSSMM_CSEx_DIS __REGVAL(SYS_SMCSSMM_CSEx, 0) +#define SYS_SMCSSMM_CSEx_EN __REGVAL(SYS_SMCSSMM_CSEx, 1) + +/* General purpose, user-defined ID register */ +#define SYS_GENID __REG(0xa0900210) + + +#define SYS_EIxCTRL(i) __REG2(0xa0900214, (i)) +#define SYS_EIxCTRL_CLEAR __REGBIT(2) +#define SYS_EIxCTRL_PLTY __REGBIT(1) +#define SYS_EIxCTRL_PLTY_HIGH __REGVAL(SYS_EIxCTRL_PLTY, 0) +#define SYS_EIxCTRL_PLTY_LOW __REGVAL(SYS_EIxCTRL_PLTY, 1) +#define SYS_EIxCTRL_TYPE __REGBIT(0) +#define SYS_EIxCTRL_TYPE_LEVEL __REGVAL(SYS_EIxCTRL_TYPE, 0) +#define SYS_EIxCTRL_TYPE_EDGE __REGVAL(SYS_EIxCTRL_TYPE, 1) + #endif /* ifndef __ASM_ARCH_REGSSYSCOMMON_H */ diff --git a/arch/arm/mach-ns9xxx/include/mach/regs-sys-ns921x.h b/arch/arm/mach-ns9xxx/include/mach/regs-sys-ns921x.h new file mode 100644 index 000000000000..a8e4410806c6 --- /dev/null +++ b/arch/arm/mach-ns9xxx/include/mach/regs-sys-ns921x.h @@ -0,0 +1,154 @@ +/* + * arch/arm/mach-ns9xxx/include/mach/regs-sys-ns921x.h + * + * Copyright (C) 2007,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. + */ +#ifndef __ASM_ARCH_REGSSYSNS921X_H +#define __ASM_ARCH_REGSSYSNS921X_H + +#include <mach/hardware.h> +#include <mach/regs-sys-common.h> + +/* System Control Module */ + +/* Timer Master Control */ +#define SYS_TMC __REG(0xa0900024) +#define SYS_TMC_T9RSE __REGBIT(21) +#define SYS_TMC_T9LSE __REGBIT(20) +#define SYS_TMC_T9HSE __REGBIT(19) +#define SYS_TMC_T8RSE __REGBIT(18) +#define SYS_TMC_T8LSE __REGBIT(17) +#define SYS_TMC_T8HSE __REGBIT(16) +#define SYS_TMC_T7RSE __REGBIT(15) +#define SYS_TMC_T7LSE __REGBIT(14) +#define SYS_TMC_T7HSE __REGBIT(13) +#define SYS_TMC_T6RSE __REGBIT(12) +#define SYS_TMC_T6LSE __REGBIT(11) +#define SYS_TMC_T6HSE __REGBIT(10) +#define SYS_TMC_T9E __REGBIT(9) +#define SYS_TMC_T8E __REGBIT(8) +#define SYS_TMC_T7E __REGBIT(7) +#define SYS_TMC_T6E __REGBIT(6) +#define SYS_TMC_T5E __REGBIT(5) +#define SYS_TMC_T4E __REGBIT(4) +#define SYS_TMC_T3E __REGBIT(3) +#define SYS_TMC_T2E __REGBIT(2) +#define SYS_TMC_T1E __REGBIT(1) +#define SYS_TMC_T0E __REGBIT(0) + +/* Timer x Reload Count and Compare register */ +#define SYS_TRCC(x) __REG2(0xa0900028, (x)) + +/* Timer x Read and Capture register */ +#define SYS_TRC(x) __REG2(0xa0900050, (x)) + +/* Interrupt Vector Address Register Level x */ +#define SYS_IVA(x) __REG2(0xa09000c4, (x)) + +/* Clock Configuration register */ +#define SYS_CLOCK __REG(0xa090017c) +#define SYS_CLOCK_CSC __REGBITS(31, 29) +#define SYS_CLOCK_CSSEL __REGBIT(25) +#define SYS_CLOCK_EXTDMA __REGBIT(14) +#define SYS_CLOCK_RTC __REGBIT(12) +#define SYS_CLOCK_I2C __REGBIT(11) +#define SYS_CLOCK_AES __REGBIT(9) +#define SYS_CLOCK_ADC __REGBIT(8) +#define SYS_CLOCK_SPI __REGBIT(5) +#define SYS_CLOCK_UARTx(i) __REGBIT(1 + (i)) +#define SYS_CLOCK_UARTD SYS_CLOCK_UARTx(3) +#define SYS_CLOCK_UARTC SYS_CLOCK_UARTx(2) +#define SYS_CLOCK_UARTB SYS_CLOCK_UARTx(1) +#define SYS_CLOCK_UARTA SYS_CLOCK_UARTx(0) +#define SYS_CLOCK_ETH __REGBIT(0) + +#define SYS_RESET __REG(0xa0900180) + +/* PLL Configuration register */ +#define SYS_PLL __REG(0xa0900188) +#define SYS_PLL_NF __REGBITS(16, 8) +#define SYS_PLL_BP __REGBIT(7) +#define SYS_PLL_OD __REGBITS(6, 5) +#define SYS_PLL_NR __REGBITS(4, 0) + +/* Timer x Control register */ +#define SYS_TC(x) __REG2(0xa0900190, (x)) +#define SYS_TCx_RELMODE __REGBIT(18) +#define SYS_TCx_RELMODE_FULL __REGVAL(SYS_TCx_RELMODE, 0) +#define SYS_TCx_RELMODE_HALF __REGVAL(SYS_TCx_RELMODE, 1) +#define SYS_TCx_MODE2 __REGBITS(17, 16) +#define SYS_TCx_MODE2_00 __REGVAL(SYS_TCx_MODE2, 0) +#define SYS_TCx_MODE2_01 __REGVAL(SYS_TCx_MODE2, 1) +#define SYS_TCx_MODE2_10 __REGVAL(SYS_TCx_MODE2, 2) +#define SYS_TCx_MODE2_11 __REGVAL(SYS_TCx_MODE2, 3) +#define SYS_TCx_TE __REGBIT(15) +#define SYS_TCx_TE_DIS __REGVAL(SYS_TCx_TE, 0) +#define SYS_TCx_TE_EN __REGVAL(SYS_TCx_TE, 1) +#define SYS_TCx_CAPCOMP __REGBITS(14,12) +#define SYS_TCx_CAPCOMP_000 __REGVAL(SYS_TCx_CAPCOMP, 0) +#define SYS_TCx_DEBUG __REGBIT(11) +#define SYS_TCx_DEBUG_CONT __REGVAL(SYS_TCx_DEBUG, 0) +#define SYS_TCx_DEBUG_STOP __REGVAL(SYS_TCx_DEBUG, 1) +#define SYS_TCx_INTCLR __REGBIT(10) +#define SYS_TCx_TCS __REGBITS(9, 6) +#define SYS_TCx_TCS_2AHB __REGVAL(SYS_TCx_TCS, 0) +#define SYS_TCx_TCS_AHB __REGVAL(SYS_TCx_TCS, 1) +#define SYS_TCx_MODE __REGBITS(5, 4) +#define SYS_TCx_MODE_INTERNAL __REGVAL(SYS_TCx_MODE, 0) +#define SYS_TCx_MODE_CONCA __REGVAL(SYS_TCx_MODE, 3) +#define SYS_TCx_INTSEL __REGBIT(3) +#define SYS_TCx_INTSEL_DIS __REGVAL(SYS_TCx_INTSEL, 0) +#define SYS_TCx_INTSEL_EN __REGVAL(SYS_TCx_INTSEL, 1) +#define SYS_TCx_UPDOWN __REGBIT(2) +#define SYS_TCx_UPDOWN_UP __REGVAL(SYS_TCx_UPDOWN, 0) +#define SYS_TCx_UPDOWN_DOWN __REGVAL(SYS_TCx_UPDOWN, 1) +#define SYS_TCx_BITTIMER __REGBIT(1) +#define SYS_TCx_BITTIMER_16 __REGVAL(SYS_TCx_BITTIMER, 0) +#define SYS_TCx_BITTIMER_32 __REGVAL(SYS_TCx_BITTIMER, 1) +#define SYS_TCx_RELENBL __REGBIT(0) +#define SYS_TCx_RELENBL_DIS __REGVAL(SYS_TCx_RELENBL, 0) +#define SYS_TCx_RELENBL_EN __REGVAL(SYS_TCx_RELENBL, 1) + +/* Timer Registers */ +#define SYS_THR(x) __REG2(0xa0900078, (x)) /* Timer 6-9 High Registers */ +#define SYS_TLR(x) __REG2(0xa0900088, (x)) /* Timer 6-9 Low Registers */ +#define SYS_THLSR(x) __REG2(0xa0900098, (x)) /* Timer 6-9 High Low Step Register */ +#define SYS_TRELSR(x) __REG2(0xa09000a8, (x)) /* Timer 6-9 Reload Step Register */ +#define SYS_TRELCCR(x) __REG2(0xa0900028, (x)) /* Timer 0-9 Reload Count and Compare Register */ +#define SYS_TRCR(x) __REG2(0xa0900050, (x)) /* Timer 0-9 Read and Capture Register */ + +/* */ +#define SYS_RTCMC __REG(0xa0900224) +#define SYS_RTCMC_SS __REGBIT(4) +#define SYS_RTCMC_RIS __REGBIT(3) +#define SYS_RTCMC_MIS __REGBIT(2) +#define SYS_RTCMC_MODE __REGBIT(1) +#define SYS_RTCMC_MODE_STANDBY __REGVAL(SYS_RTCMC_MODE, 0) +#define SYS_RTCMC_MODE_NORMAL __REGVAL(SYS_RTCMC_MODE, 1) +#define SYS_RTCMC_RIC __REGBIT(0) + +/* */ +#define SYS_POWER __REG(0xa0900228) +#define SYS_POWER_SLFRFSH __REGBIT(21) +#define SYS_POWER_INTCLR __REGBIT(20) +#define SYS_POWER_EXTIRQx(i) __REGBIT(16 + (i)) +#define SYS_POWER_EXTIRQ3 SYS_POWER_EXTIRQx(3) +#define SYS_POWER_EXTIRQ2 SYS_POWER_EXTIRQx(2) +#define SYS_POWER_EXTIRQ1 SYS_POWER_EXTIRQx(1) +#define SYS_POWER_EXTIRQ0 SYS_POWER_EXTIRQx(0) +#define SYS_POWER_RTC SYS_CLOCK_RTC +#define SYS_POWER_I2C SYS_CLOCK_I2C +#define SYS_POWER_SPI SYS_CLOCK_SPI +#define SYS_POWER_UARTx(i) SYS_CLOCK_UARTx(i) +#define SYS_POWER_UARTD SYS_POWER_UARTx(3) +#define SYS_POWER_UARTC SYS_POWER_UARTx(2) +#define SYS_POWER_UARTB SYS_POWER_UARTx(1) +#define SYS_POWER_UARTA SYS_POWER_UARTx(0) +#define SYS_POWER_ETH SYS_CLOCK_ETH + +#endif /* ifndef __ASM_ARCH_REGSSYSNS921X_H */ diff --git a/arch/arm/mach-ns9xxx/include/mach/regs-sys-ns9360.h b/arch/arm/mach-ns9xxx/include/mach/regs-sys-ns9360.h index 8ff254d9901c..30236e6fbc49 100644 --- a/arch/arm/mach-ns9xxx/include/mach/regs-sys-ns9360.h +++ b/arch/arm/mach-ns9xxx/include/mach/regs-sys-ns9360.h @@ -1,7 +1,7 @@ /* * arch/arm/mach-ns9xxx/include/mach/regs-sys-ns9360.h * - * Copyright (C) 2006,2007 by Digi International Inc. + * Copyright (C) 2006-2008 by Digi International Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify it @@ -30,6 +30,12 @@ /* Timer Interrupt Status register */ #define SYS_TIS __REG(0xa0900170) +#define SYS_CLOCK __REG(0xa090017c) +#define SYS_CLOCK_LPCSEXT __REGBIT(9) + +#define SYS_RESET __REG(0xa0900180) +#define SYS_RESET_LCDC __REGBIT(5) + /* PLL Configuration register */ #define SYS_PLL __REG(0xa0900188) @@ -100,32 +106,6 @@ #define SYS_TCx_REN_DIS __REGVAL(SYS_TCx_REN, 0) #define SYS_TCx_REN_EN __REGVAL(SYS_TCx_REN, 1) -/* System Memory Chip Select x Dynamic Memory Base */ -#define SYS_SMCSDMB(x) __REG2(0xa09001d0, (x) << 1) - -/* System Memory Chip Select x Dynamic Memory Mask */ -#define SYS_SMCSDMM(x) __REG2(0xa09001d4, (x) << 1) - -/* System Memory Chip Select x Static Memory Base */ -#define SYS_SMCSSMB(x) __REG2(0xa09001f0, (x) << 1) - -/* System Memory Chip Select x Static Memory Base: Chip select x base */ -#define SYS_SMCSSMB_CSxB __REGBITS(31, 12) - -/* System Memory Chip Select x Static Memory Mask */ -#define SYS_SMCSSMM(x) __REG2(0xa09001f4, (x) << 1) - -/* System Memory Chip Select x Static Memory Mask: Chip select x mask */ -#define SYS_SMCSSMM_CSxM __REGBITS(31, 12) - -/* System Memory Chip Select x Static Memory Mask: Chip select x enable */ -#define SYS_SMCSSMM_CSEx __REGBIT(0) -#define SYS_SMCSSMM_CSEx_DIS __REGVAL(SYS_SMCSSMM_CSEx, 0) -#define SYS_SMCSSMM_CSEx_EN __REGVAL(SYS_SMCSSMM_CSEx, 1) - -/* General purpose, user-defined ID register */ -#define SYS_GENID __REG(0xa0900210) - /* External Interrupt x Control register */ #define SYS_EIC(x) __REG2(0xa0900214, (x)) @@ -145,4 +125,7 @@ #define SYS_EIC_LVEDG_LEVEL __REGVAL(SYS_EIC_LVEDG, 0) #define SYS_EIC_LVEDG_EDGE __REGVAL(SYS_EIC_LVEDG, 1) +/* RTC Clock Control register */ +#define SYS_RTCCC __REG(0xa0900224) + #endif /* ifndef __ASM_ARCH_REGSSYSNS9360_H */ diff --git a/arch/arm/mach-ns9xxx/include/mach/spi.h b/arch/arm/mach-ns9xxx/include/mach/spi.h new file mode 100644 index 000000000000..801d01b838d6 --- /dev/null +++ b/arch/arm/mach-ns9xxx/include/mach/spi.h @@ -0,0 +1,28 @@ +/* + * arch/arm/mach-ns9xxx/include/mach/spi.h + * + * 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. +*/ +#ifndef __ASM_ARCH_SPI_H +#define __ASM_ARCH_SPI_H + +#define SPI_MOSI_GPIO_OFFSET 0 +#define SPI_MISO_GPIO_OFFSET 1 +#define SPI_CLK_GPIO_OFFSET 2 +#define SPI_EN_GPIO_OFFSET 3 + + +#define SPI_MAX_GPIO 10 + +struct spi_ns9xxx_data { + char gpios[SPI_MAX_GPIO]; + char gpio_funcs[SPI_MAX_GPIO]; + char nr_gpios; +}; + +#endif /* ifndef __ASM_ARCH_SPI_H */ diff --git a/arch/arm/mach-ns9xxx/include/mach/system.h b/arch/arm/mach-ns9xxx/include/mach/system.h index e2068c57415f..e4ae479dc5b2 100644 --- a/arch/arm/mach-ns9xxx/include/mach/system.h +++ b/arch/arm/mach-ns9xxx/include/mach/system.h @@ -1,7 +1,7 @@ /* * arch/arm/mach-ns9xxx/include/mach/system.h * - * Copyright (C) 2006,2007 by Digi International Inc. + * Copyright (C) 2006-2008 by Digi International Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify it @@ -13,15 +13,32 @@ #include <asm/proc-fns.h> #include <mach/processor.h> -#include <mach/processor-ns9360.h> static inline void arch_idle(void) { - cpu_do_idle(); + /* + * When a Camry (i.e. ns921x) executes + * + * mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt + * + * the CPU is stopped, so are all timers. This is not something I want + * to handle. As the "wait for interrupt" instruction is part of + * cpu_arm926_do_idle, it's not called for it. + */ + if (!processor_is_ns921x()) + cpu_do_idle(); } +void ns921x_reset(char); +void ns9360_reset(char); + static inline void arch_reset(char mode) { +#ifdef CONFIG_PROCESSOR_NS921X + if (processor_is_ns921x()) + ns921x_reset(mode); + else +#endif #ifdef CONFIG_PROCESSOR_NS9360 if (processor_is_ns9360()) ns9360_reset(mode); diff --git a/arch/arm/mach-ns9xxx/include/mach/timex.h b/arch/arm/mach-ns9xxx/include/mach/timex.h index 734a8d8bd578..e901b4e10610 100644 --- a/arch/arm/mach-ns9xxx/include/mach/timex.h +++ b/arch/arm/mach-ns9xxx/include/mach/timex.h @@ -12,7 +12,7 @@ #define __ASM_ARCH_TIMEX_H /* - * value for CLOCK_TICK_RATE stolen from arch/arm/mach-s3c2410/include/mach/timex.h. + * value for CLOCK_TICK_RATE stolen from include/asm-arm/arch-s3c2410/timex.h. * See there for an explanation. */ #define CLOCK_TICK_RATE 12000000 diff --git a/arch/arm/mach-ns9xxx/include/mach/uncompress.h b/arch/arm/mach-ns9xxx/include/mach/uncompress.h index 1b12d324b087..fc9b0a424230 100644 --- a/arch/arm/mach-ns9xxx/include/mach/uncompress.h +++ b/arch/arm/mach-ns9xxx/include/mach/uncompress.h @@ -11,15 +11,21 @@ #ifndef __ASM_ARCH_UNCOMPRESS_H #define __ASM_ARCH_UNCOMPRESS_H -#include <linux/io.h> - -#define __REG(x) ((void __iomem __force *)(x)) +#include <asm/io.h> +#define __REG(x) ((void __iomem __force *)(x)) static void putc_dummy(char c, void __iomem *base) { /* nothing */ } +#if defined(CONFIG_PROCESSOR_NS9360) +# define NS9360_UARTA __REG(0x90200040) +# define NS9360_UARTB __REG(0x90200000) +# define NS9360_UARTC __REG(0x90300000) +# define NS9360_UARTD __REG(0x90300040) +# define NS9360_UART_ENABLED(base) \ + (__raw_readl(NS9360_UARTA) & (1 << 31)) static void putc_ns9360(char c, void __iomem *base) { static int t = 0x10000; @@ -34,22 +40,16 @@ static void putc_ns9360(char c, void __iomem *base) } } while (t); } - -static void putc_a9m9750dev(char c, void __iomem *base) -{ - static int t = 0x10000; - do { - if (t) - --t; - - if (__raw_readb(base + 5) & (1 << 5)) { - __raw_writeb(c, base); - t = 0x10000; - break; - } - } while (t); - -} +#endif + +#if defined(CONFIG_PROCESSOR_NS921X) +# define NS921XSYS_CLOCK __REG(0xa090017c) +# define NS921X_UARTA __REG(0x90010000) +# define NS921X_UARTB __REG(0x90018000) +# define NS921X_UARTC __REG(0x90020000) +# define NS921X_UARTD __REG(0x90028000) +# define NS921X_UART_ENABLED(base) \ + (__raw_readl((base) + 0x1000) & (1 << 29)) static void putc_ns921x(char c, void __iomem *base) { @@ -66,79 +66,96 @@ static void putc_ns921x(char c, void __iomem *base) } while (t); } -#define MSCS __REG(0xA0900184) +#include "fim-uncompress.h" -#define NS9360_UARTA __REG(0x90200040) -#define NS9360_UARTB __REG(0x90200000) -#define NS9360_UARTC __REG(0x90300000) -#define NS9360_UARTD __REG(0x90300040) +static void putc_ns921x_fim(char ch, void __iomem *base) +{ + unsigned int status; + unsigned short data = 1; + int pic = 0; -#define NS9360_UART_ENABLED(base) \ - (__raw_readl(NS9360_UARTA) & (1 << 31)) + if ('\n' == ch) + ch = '\r'; -#define A9M9750DEV_UARTA __REG(0x40000000) + data = (data << FIM_SERIAL_DATA_BITS) | (ch & ((1 << FIM_SERIAL_DATA_BITS) - 1)); -#define NS921XSYS_CLOCK __REG(0xa090017c) -#define NS921X_UARTA __REG(0x90010000) -#define NS921X_UARTB __REG(0x90018000) -#define NS921X_UARTC __REG(0x90020000) -#define NS921X_UARTD __REG(0x90028000) + /* Check if the PIC is tasked with another send-char request */ + do { + status = fim_get_exp_reg(pic, 0); + } while (status & FIM_SERIAL_INT_INSERT_CHAR); -#define NS921X_UART_ENABLED(base) \ - (__raw_readl((base) + 0x1000) & (1 << 29)) + /* And send the char using the interrupt function */ + fim_set_ctrl_reg(pic, 0, data & 0xFF); + fim_set_ctrl_reg(pic, 1, (data >> 8) & 0xFF); + fim_send_interrupt(pic, FIM_SERIAL_INT_INSERT_CHAR); +} +#endif static void autodetect(void (**putc)(char, void __iomem *), void __iomem **base) { - if (((__raw_readl(MSCS) >> 16) & 0xfe) == 0x00) { - /* ns9360 or ns9750 */ - if (NS9360_UART_ENABLED(NS9360_UARTA)) { - *putc = putc_ns9360; - *base = NS9360_UARTA; - return; - } else if (NS9360_UART_ENABLED(NS9360_UARTB)) { - *putc = putc_ns9360; - *base = NS9360_UARTB; - return; - } else if (NS9360_UART_ENABLED(NS9360_UARTC)) { - *putc = putc_ns9360; - *base = NS9360_UARTC; - return; - } else if (NS9360_UART_ENABLED(NS9360_UARTD)) { - *putc = putc_ns9360; - *base = NS9360_UARTD; - return; - } else if (__raw_readl(__REG(0xa09001f4)) == 0xfffff001) { - *putc = putc_a9m9750dev; - *base = A9M9750DEV_UARTA; - return; - } - } else if (((__raw_readl(MSCS) >> 16) & 0xfe) == 0x02) { - /* ns921x */ - u32 clock = __raw_readl(NS921XSYS_CLOCK); - - if ((clock & (1 << 1)) && - NS921X_UART_ENABLED(NS921X_UARTA)) { - *putc = putc_ns921x; - *base = NS921X_UARTA; - return; - } else if ((clock & (1 << 2)) && - NS921X_UART_ENABLED(NS921X_UARTB)) { - *putc = putc_ns921x; - *base = NS921X_UARTB; - return; - } else if ((clock & (1 << 3)) && - NS921X_UART_ENABLED(NS921X_UARTC)) { - *putc = putc_ns921x; - *base = NS921X_UARTC; - return; - } else if ((clock & (1 << 4)) && - NS921X_UART_ENABLED(NS921X_UARTD)) { - *putc = putc_ns921x; - *base = NS921X_UARTD; - return; - } +#if defined(CONFIG_PROCESSOR_NS9360) + /* ns9360 */ + if (NS9360_UART_ENABLED(NS9360_UARTA)) { + *putc = putc_ns9360; + *base = NS9360_UARTA; + return; + } else if (NS9360_UART_ENABLED(NS9360_UARTB)) { + *putc = putc_ns9360; + *base = NS9360_UARTB; + return; + } else if (NS9360_UART_ENABLED(NS9360_UARTC)) { + *putc = putc_ns9360; + *base = NS9360_UARTC; + return; + } else if (NS9360_UART_ENABLED(NS9360_UARTD)) { + *putc = putc_ns9360; + *base = NS9360_UARTD; + return; } - +#elif defined(CONFIG_PROCESSOR_NS921X) + /* ns921x */ + u32 clock = __raw_readl(NS921XSYS_CLOCK); + + if ((clock & (1 << 1)) && + NS921X_UART_ENABLED(NS921X_UARTA)) { + *putc = putc_ns921x; + *base = NS921X_UARTA; + return; + } else if ((clock & (1 << 2)) && + NS921X_UART_ENABLED(NS921X_UARTB)) { + *putc = putc_ns921x; + *base = NS921X_UARTB; + return; + } else if ((clock & (1 << 3)) && + NS921X_UART_ENABLED(NS921X_UARTC)) { + *putc = putc_ns921x; + *base = NS921X_UARTC; + return; + } else if ((clock & (1 << 4)) && + NS921X_UART_ENABLED(NS921X_UARTD)) { + *putc = putc_ns921x; + *base = NS921X_UARTD; + return; + } +# if defined(CONFIG_SERIAL_FIM_CONSOLE) + /* None of the standard UARTs is enabled. Try with the FIMs */ +# if defined(CONFIG_FIM_ZERO_SERIAL_SELECTED) && !defined(CONFIG_FIM_ONE_SERIAL_SELECTED) + /* Try with UART on FIM0 */ + else if (NS921X_FIM_ENABLED(NS921X_FIM0)) { + *putc = putc_ns921x_fim; + *base = NS921X_FIM0; + return; + } +# elif !defined(CONFIG_FIM_ZERO_SERIAL_SELECTED) && defined(CONFIG_FIM_ONE_SERIAL_SELECTED) + /* Try with UART on FIM1 */ + else if (NS921X_FIM_ENABLED(NS921X_FIM1)) { + *putc = putc_ns921x_fim; + *base = NS921X_FIM1; + return; + } +# endif /* FIM_x */ +# endif /* SERIAL_FIM_CONSOLE */ +#endif /* PROCESSOR_x */ *putc = putc_dummy; } @@ -147,7 +164,7 @@ void __iomem *base; static void putc(char c) { - myputc(c, base); + myputc(c, base); } static void arch_decomp_setup(void) diff --git a/arch/arm/mach-ns9xxx/irq-ns921x.c b/arch/arm/mach-ns9xxx/irq-ns921x.c new file mode 100644 index 000000000000..1937d574a0e3 --- /dev/null +++ b/arch/arm/mach-ns9xxx/irq-ns921x.c @@ -0,0 +1,57 @@ +/* + * arch/arm/mach-ns9xxx/irq-ns921x.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/errno.h> +#include <linux/kernel.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <mach/regs-sys-ns921x.h> + +#include "processor-ns921x.h" + +static const u32 ns921x_irq2powermask[] = { + [IRQ_NS9XXX_ETHRX] = SYS_POWER_ETH, + [IRQ_NS921X_UARTA] = SYS_POWER_UARTA, + [IRQ_NS921X_UARTB] = SYS_POWER_UARTB, + [IRQ_NS921X_UARTC] = SYS_POWER_UARTC, + [IRQ_NS921X_UARTD] = SYS_POWER_UARTD, + [IRQ_NS921X_SPI] = SYS_POWER_SPI, + [IRQ_NS921X_I2C] = SYS_POWER_I2C, + [IRQ_NS9215_RTC] = SYS_POWER_RTC, + [IRQ_NS9XXX_EXT0] = SYS_POWER_EXTIRQ0, + [IRQ_NS9XXX_EXT1] = SYS_POWER_EXTIRQ1, + [IRQ_NS9XXX_EXT2] = SYS_POWER_EXTIRQ2, + [IRQ_NS9XXX_EXT3] = SYS_POWER_EXTIRQ3, +}; + +int ns921x_set_wake_irq(unsigned int irq, unsigned int on) +{ + unsigned long flags; + u32 power; + + if (irq > ARRAY_SIZE(ns921x_irq2powermask) || + !ns921x_irq2powermask[irq]) + return -ENOENT; + + local_irq_save(flags); + + power = __raw_readl(SYS_POWER); + + if (on) + power |= ns921x_irq2powermask[irq]; + else + power &= ~ns921x_irq2powermask[irq]; + + __raw_writel(power, SYS_POWER); + + local_irq_restore(flags); + + return 0; +} diff --git a/arch/arm/mach-ns9xxx/irq.c b/arch/arm/mach-ns9xxx/irq.c index 22e0eb6e9ec4..e678f53cca61 100644 --- a/arch/arm/mach-ns9xxx/irq.c +++ b/arch/arm/mach-ns9xxx/irq.c @@ -1,7 +1,7 @@ /* * arch/arm/mach-ns9xxx/irq.c * - * Copyright (C) 2006,2007 by Digi International Inc. + * Copyright (C) 2006-2008 by Digi International Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify it @@ -10,30 +10,105 @@ */ #include <linux/interrupt.h> #include <linux/kernel_stat.h> -#include <linux/io.h> +#include <asm/io.h> #include <asm/mach/irq.h> +#include <asm/mach-types.h> +#include <mach/regs-bbu.h> #include <mach/regs-sys-common.h> #include <mach/irqs.h> #include <mach/board.h> +#include <mach/processor.h> -#include "generic.h" +#include "processor-ns921x.h" +#include "irq.h" -/* simple interrupt prio table: prio(x) < prio(y) <=> x < y */ -#define irq2prio(i) (i) -#define prio2irq(p) (p) +static unsigned prio2irq(unsigned prio) +{ + u32 ic = __raw_readl(SYS_IC(prio / 4)); + return REGGETIM_IDX(ic, SYS_IC, ISD, __SYS_IC_FIELDNUM(prio)); +} + +static unsigned irq2prio_map[32]; + +static unsigned irq2prio(unsigned irq) +{ + unsigned cachedprio = irq2prio_map[irq]; + int timeout; + + if (likely(irq == prio2irq(cachedprio))) + return cachedprio; + + for (timeout = 32; timeout; --timeout) { + static unsigned i; + unsigned iirq; + + i = (i + 1) % 32; + + iirq = prio2irq(i); + + irq2prio_map[iirq] = i; + + pr_debug("%s: update %u -> %u\n", __func__, iirq, i); + + if (iirq == irq) + return i; + } + + BUG(); + + return 0; /* not reached, clean compiler warning */ +} + +#define prio2irq_init(p) (p) static void ns9xxx_mask_irq(unsigned int irq) { - /* XXX: better use cpp symbols */ int prio = irq2prio(irq); u32 ic = __raw_readl(SYS_IC(prio / 4)); - ic &= ~(1 << (7 + 8 * (3 - (prio & 3)))); + REGSET_IDX(ic, SYS_IC, IE, __SYS_IC_FIELDNUM(prio), DIS); __raw_writel(ic, SYS_IC(prio / 4)); } +int ns9xxx_is_enabled_irq(unsigned int irq) +{ + int prio = irq2prio(irq); + u32 ic, en_bit_mask; + + en_bit_mask = 0x80 << ((3 - (prio & 3)) * 8); + ic = __raw_readl(SYS_IC(prio / 4)); + + return ic & en_bit_mask; +} +EXPORT_SYMBOL(ns9xxx_is_enabled_irq); + +static void ns9xxx_disable_irq(unsigned int irq) +{ + struct irq_desc *desc = irq_desc + irq; + + ns9xxx_mask_irq(irq); + desc->status &= IRQ_MASKED; +} + static void ns9xxx_ack_irq(unsigned int irq) { - __raw_writel(0, SYS_ISRADDR); + if (irq >= IRQ_NS9XXX_EXT0) { + u32 eixctl; + + BUG_ON((unsigned)(irq - IRQ_NS9XXX_EXT0) > 4); + + eixctl = __raw_readl(SYS_EIxCTRL(irq - IRQ_NS9XXX_EXT0)); + + if (REGGET(eixctl, SYS_EIxCTRL, TYPE) == + SYS_EIxCTRL_TYPE_EDGE) { + REGSETIM(eixctl, SYS_EIxCTRL, CLEAR, 1); + __raw_writel(eixctl, + SYS_EIxCTRL(irq - IRQ_NS9XXX_EXT0)); + + REGSETIM(eixctl, SYS_EIxCTRL, CLEAR, 0); + __raw_writel(eixctl, + SYS_EIxCTRL(irq - IRQ_NS9XXX_EXT0)); + } + } } static void ns9xxx_maskack_irq(unsigned int irq) @@ -44,23 +119,175 @@ static void ns9xxx_maskack_irq(unsigned int irq) static void ns9xxx_unmask_irq(unsigned int irq) { - /* XXX: better use cpp symbols */ int prio = irq2prio(irq); u32 ic = __raw_readl(SYS_IC(prio / 4)); - ic |= 1 << (7 + 8 * (3 - (prio & 3))); + REGSET_IDX(ic, SYS_IC, IE, __SYS_IC_FIELDNUM(prio), EN); __raw_writel(ic, SYS_IC(prio / 4)); } +static void ns9xxx_eoi_irq(unsigned int irq) +{ + __raw_writel(irq2prio(irq), SYS_ISRADDR); +} + +static int ns9xxx_set_type_irq(unsigned int irq, unsigned int flow_type) +{ + void __iomem *regeixctrl = SYS_EIxCTRL(irq - IRQ_NS9XXX_EXT0); + u32 eixctrl = 0; + + REGSETIM(eixctrl, SYS_EIxCTRL, CLEAR, 1); + + if (irq < IRQ_NS9XXX_EXT0 || irq > IRQ_NS9XXX_EXT3) + return -EINVAL; + + switch (flow_type) { + case IRQF_TRIGGER_HIGH: + REGSET(eixctrl, SYS_EIxCTRL, PLTY, HIGH); + REGSET(eixctrl, SYS_EIxCTRL, TYPE, LEVEL); + break; + + case IRQF_TRIGGER_LOW: + REGSET(eixctrl, SYS_EIxCTRL, PLTY, LOW); + REGSET(eixctrl, SYS_EIxCTRL, TYPE, LEVEL); + break; + + case IRQF_TRIGGER_RISING: + REGSET(eixctrl, SYS_EIxCTRL, PLTY, HIGH); + REGSET(eixctrl, SYS_EIxCTRL, TYPE, EDGE); + break; + + case IRQF_TRIGGER_FALLING: + REGSET(eixctrl, SYS_EIxCTRL, PLTY, LOW); + REGSET(eixctrl, SYS_EIxCTRL, TYPE, EDGE); + break; + + default: + pr_warning("%s: cannot configure for flow type %u\n", + __func__, flow_type); + return -ENODEV; + } + + __raw_writel(eixctrl, regeixctrl); + REGSETIM(eixctrl, SYS_EIxCTRL, CLEAR, 0); + __raw_writel(eixctrl, regeixctrl); + + return 0; +} + +static int ns9xxx_set_wake_irq(unsigned int irq, unsigned int on) +{ +#if defined(CONFIG_PROCESSOR_NS921X) + if (processor_is_ns921x()) + return ns921x_set_wake_irq(irq, on); +#endif + + return -EINVAL; +} + static struct irq_chip ns9xxx_chip = { + .name = "ns9xxx", + .disable = ns9xxx_disable_irq, .ack = ns9xxx_ack_irq, .mask = ns9xxx_mask_irq, .mask_ack = ns9xxx_maskack_irq, .unmask = ns9xxx_unmask_irq, + .eoi = ns9xxx_eoi_irq, + .set_type = ns9xxx_set_type_irq, + .set_wake = ns9xxx_set_wake_irq, +}; + +#if defined(CONFIG_PROCESSOR_NS9360) +static void ns9360_mask_bbus_irq(unsigned int irq) +{ + u32 ier = __raw_readl(NS9360_BBUS_IEN); + ier &= ~(1 << (irq - IRQ_NS9360_BBUS(0))); + __raw_writel(ier, NS9360_BBUS_IEN); +} + +static void ns9360_unmask_bbus_irq(unsigned int irq) +{ + u32 ier = __raw_readl(NS9360_BBUS_IEN); + ier |= 1 << (irq - IRQ_NS9360_BBUS(0)); + __raw_writel(ier, NS9360_BBUS_IEN); +} + +static void ns9360_demux_bbus_irq(unsigned int irq, struct irq_desc *desc) +{ + unsigned bbus_irq_plus1; + u32 stat = __raw_readl(NS9360_BBUS_ISTAT); + + while ((bbus_irq_plus1 = fls(stat))) { + unsigned bbus_irq = bbus_irq_plus1 - 1; + stat &= ~(1 << bbus_irq); + + desc_handle_irq(IRQ_NS9360_BBUS(bbus_irq), + irq_desc + IRQ_NS9360_BBUS(bbus_irq)); + } + + /* unmask parent irq */ + desc->chip->unmask(irq); + desc->chip->eoi(irq); +} + +static struct irq_chip ns9360_bbus_chip = { + .name = "ns9xxx_bbus", + .ack = ns9360_mask_bbus_irq, + .mask = ns9360_mask_bbus_irq, + .mask_ack = ns9360_mask_bbus_irq, + .unmask = ns9360_unmask_bbus_irq, +}; + +static void ns9360_mask_bbus_dma_irq(unsigned int irq) +{ + u32 ien = __raw_readl(NS9360_BBUS_DMA_IEN); + ien &= ~(1 << (irq - IRQ_NS9360_BBUDMA(0))); + __raw_writel(ien, NS9360_BBUS_DMA_IEN); +} + +static void ns9360_unmask_bbus_dma_irq( unsigned int irq ) +{ + u32 ien = __raw_readl(NS9360_BBUS_DMA_IEN); + ien |= 1 << (irq - IRQ_NS9360_BBUDMA(0)); + __raw_writel(ien, NS9360_BBUS_DMA_IEN); +} + +static void ns9360_demux_bbus_dma_irq(unsigned int irq, struct irq_desc *desc) +{ + unsigned dma_irq_plus1; + u32 stat = __raw_readl(NS9360_BBUS_DMA_ISTAT); + + /* mask parent irq */ + desc->chip->mask_ack(irq); + + while ((dma_irq_plus1 = fls(stat))) { + unsigned dma_irq = dma_irq_plus1 - 1; + stat &= ~(1 << dma_irq); + + desc_handle_irq(IRQ_NS9360_BBUDMA(dma_irq), + irq_desc + IRQ_NS9360_BBUDMA(dma_irq)); + } + + /* unmask parent */ + desc->chip->unmask(irq); +} + +static struct irq_chip ns9360_bbus_dma_chip = { + .name = "ns9xxx_bbus_dma", + .ack = ns9360_mask_bbus_dma_irq, + .mask = ns9360_mask_bbus_dma_irq, + .mask_ack = ns9360_mask_bbus_dma_irq, + .unmask = ns9360_unmask_bbus_dma_irq, }; +#endif /* if defined(CONFIG_PROCESSOR_NS9360) */ + +extern int noirqdebug; -#if 0 -#define handle_irq handle_level_irq -#else +/* this is similar to handle_fasteoi_irq. The differences are: + * - handle_prio_irq calls desc->chip->ack at the beginning; + * - handle_prio_irq disables an irq directly after handle_IRQ_event to work + * around the bug in the ns9xxx' irq priority encoder; + * - currently some debug code; + */ static void handle_prio_irq(unsigned int irq, struct irq_desc *desc) { unsigned int cpu = smp_processor_id(); @@ -69,24 +296,29 @@ static void handle_prio_irq(unsigned int irq, struct irq_desc *desc) spin_lock(&desc->lock); - BUG_ON(desc->status & IRQ_INPROGRESS); + desc->chip->ack(irq); + + if (unlikely(desc->status & IRQ_INPROGRESS)) { + desc->status |= IRQ_PENDING; + goto out_unlock; + } desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); kstat_cpu(cpu).irqs[irq]++; action = desc->action; - if (unlikely(!action || (desc->status & IRQ_DISABLED))) + if (unlikely(!action || (desc->status & IRQ_DISABLED))) { + desc->status |= IRQ_PENDING; goto out_mask; + } desc->status |= IRQ_INPROGRESS; + desc->status &= ~IRQ_PENDING; spin_unlock(&desc->lock); action_ret = handle_IRQ_event(irq, action); - - /* XXX: There is no direct way to access noirqdebug, so check - * unconditionally for spurious irqs... - * Maybe this function should go to kernel/irq/chip.c? */ - note_interrupt(irq, desc, action_ret); + if (!noirqdebug) + note_interrupt(irq, desc, action_ret); spin_lock(&desc->lock); desc->status &= ~IRQ_INPROGRESS; @@ -95,32 +327,62 @@ static void handle_prio_irq(unsigned int irq, struct irq_desc *desc) out_mask: desc->chip->mask(irq); - /* ack unconditionally to unmask lower prio irqs */ - desc->chip->ack(irq); + desc->chip->eoi(irq); +out_unlock: spin_unlock(&desc->lock); } -#define handle_irq handle_prio_irq -#endif void __init ns9xxx_init_irq(void) { int i; /* disable all IRQs */ - for (i = 0; i < 8; ++i) - __raw_writel(prio2irq(4 * i) << 24 | - prio2irq(4 * i + 1) << 16 | - prio2irq(4 * i + 2) << 8 | - prio2irq(4 * i + 3), - SYS_IC(i)); + for (i = 0; i < 8; ++i) { + u32 ic = 0; + + REGSETIM_IDX(ic, SYS_IC, ISD, __SYS_IC_FIELDNUM(0), + prio2irq_init(4 * i)); + REGSETIM_IDX(ic, SYS_IC, ISD, __SYS_IC_FIELDNUM(1), + prio2irq_init(4 * i + 1)); + REGSETIM_IDX(ic, SYS_IC, ISD, __SYS_IC_FIELDNUM(2), + prio2irq_init(4 * i + 2)); + REGSETIM_IDX(ic, SYS_IC, ISD, __SYS_IC_FIELDNUM(3), + prio2irq_init(4 * i + 3)); + + __raw_writel(ic, SYS_IC(i)); + } for (i = 0; i < 32; ++i) __raw_writel(prio2irq(i), SYS_IVA(i)); for (i = 0; i <= 31; ++i) { set_irq_chip(i, &ns9xxx_chip); - set_irq_handler(i, handle_irq); + set_irq_handler(i, handle_prio_irq); set_irq_flags(i, IRQF_VALID); } + +#ifdef CONFIG_PROCESSOR_NS9360 + if (processor_is_ns9360()) { + /* set up the BBUS interrupt handlers */ + __raw_writel(NS9360_BBUS_IEN_GLBL, NS9360_BBUS_IEN); + for (i = IRQ_NS9360_BBUS(0); i <= IRQ_NS9360_BBUS(25); i++) { + set_irq_chip(i, &ns9360_bbus_chip); + set_irq_handler(i, handle_level_irq); + set_irq_flags(i, IRQF_VALID); + } + set_irq_chained_handler(IRQ_NS9360_BBUSAGG, + ns9360_demux_bbus_irq); + + /* set up the BBUS DMA interrupt handlers */ + __raw_writel(0, NS9360_BBUS_DMA_IEN); + for (i = IRQ_NS9360_BBUDMA(0); i <= IRQ_NS9360_BBUDMA(15); i++) { + set_irq_chip(i, &ns9360_bbus_dma_chip); + set_irq_handler(i, handle_level_irq); + set_irq_flags(i, IRQF_VALID); + } + set_irq_chained_handler(IRQ_NS9360_BBUS_DMA, + ns9360_demux_bbus_dma_irq); + } +#endif } diff --git a/arch/arm/mach-ns9xxx/irq.h b/arch/arm/mach-ns9xxx/irq.h new file mode 100644 index 000000000000..81f4487a8cd2 --- /dev/null +++ b/arch/arm/mach-ns9xxx/irq.h @@ -0,0 +1,16 @@ +/* + * arch/arm/mach-ns9xxx/irq.h + * + * 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/time.h> +#include <asm/mach/time.h> +#include <linux/init.h> + +void __init ns9xxx_init_irq(void); diff --git a/arch/arm/mach-ns9xxx/leds.c b/arch/arm/mach-ns9xxx/leds.c new file mode 100644 index 000000000000..99414dce0437 --- /dev/null +++ b/arch/arm/mach-ns9xxx/leds.c @@ -0,0 +1,64 @@ +/* + * arch/arm/mach-ns9xxx/leds.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/init.h> +#include <linux/kernel.h> +#include <linux/gpio.h> + +#include <asm/leds.h> + +#include <mach/module.h> + +static void cc9p9215_leds_event(led_event_t evt) +{ + switch(evt) { + case led_idle_start: + gpio_set_value(89, 1); + break; + case led_idle_end: + gpio_set_value(89, 0); + break; + case led_green_on: + if (module_is_ccw9p9215()) + gpio_set_value(88, 0); + break; + case led_green_off: + if (module_is_ccw9p9215()) + gpio_set_value(88, 1); + break; + default: + break; + } +} + +static int __init ns9xxx_init_leds(void) +{ + int ret; + + if (!module_is_cc9p9215() && !module_is_ccw9p9215()) + return -ENODEV; + + ret = gpio_request(89, "idle led"); + if (ret) + return ret; + + if (module_is_ccw9p9215()) { + ret = gpio_request(88, "wifi led"); + if (ret) + return ret; + /* switch the led, just in case it were on */ + gpio_set_value(88, 1); + } + + leds_event = cc9p9215_leds_event; + + return 0; +} +device_initcall(ns9xxx_init_leds); diff --git a/arch/arm/mach-ns9xxx/mach-cc7ucamry.c b/arch/arm/mach-ns9xxx/mach-cc7ucamry.c new file mode 100644 index 000000000000..741cc8974d7b --- /dev/null +++ b/arch/arm/mach-ns9xxx/mach-cc7ucamry.c @@ -0,0 +1,23 @@ +/* + * arch/arm/mach-ns9xxx/mach-cc7ucamry.c + * + * Copyright (C) 2007 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 <asm/mach/arch.h> +#include <asm/mach-types.h> + +#include "irq.h" +#include "processor-ns921x.h" + +MACHINE_START(CC7UCAMRY, "ConnectCore 7U Camry") + .map_io = ns921x_map_io, + .init_irq = ns9xxx_init_irq, + .init_machine = ns921x_init_machine, + .timer = &ns921x_timer, + .boot_params = 0x100, +MACHINE_END diff --git a/arch/arm/mach-ns9xxx/mach-cc9c.c b/arch/arm/mach-ns9xxx/mach-cc9c.c new file mode 100644 index 000000000000..08561d0441b6 --- /dev/null +++ b/arch/arm/mach-ns9xxx/mach-cc9c.c @@ -0,0 +1,176 @@ +/* + * arch/arm/mach-ns9xxx/mach-cc9c.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/i2c.h> +#include <linux/i2c/pca953x.h> +#include <linux/spi/spi.h> +#include <linux/spi/ads7846.h> +#include <linux/gpio.h> + +#include <asm/mach/arch.h> +#include <asm/mach-types.h> + +#include "irq.h" +#include "processor-ns9360.h" +#include "ns9360_devices.h" +#include "ccx9c_devices.h" + +/* I2C devices */ +#if defined(CONFIG_GPIO_PCA953X) || defined(CONFIG_GPIO_PCA953X_MODULE) +static struct pca953x_platform_data pca9554_data = { + .gpio_base = 108, +}; +#endif + +static struct i2c_board_info i2c_devices[] __initdata = { +#if defined(CONFIG_GPIO_PCA953X) || defined(CONFIG_GPIO_PCA953X_MODULE) + { + I2C_BOARD_INFO("pca9554", 0x20), + .platform_data = &pca9554_data, + }, +#endif +}; + +#ifdef CONFIG_CCX9C_TOUCH +static int touch_pendown_state(void) +{ + return gpio_get_value(18) ? 0 : 1; +} + +static struct ads7846_platform_data ccx9c_touch_data = { + .model = 7843, + .get_pendown_state = touch_pendown_state, + .x_min = 100, + .y_min = 100, + .x_max = 4000, + .y_max = 4000, + .rotate = 180, + .buflen = 20, + .skip_samples = 0, +}; + +void __init ccx9c_add_device_touch(void) +{ + if (gpio_request(18, "ads7846")) + return; + + gpio_configure_ns9360(18, 0, 0, 2); +} + +#define CCX9C_SPI_TOUCH \ + { \ + .modalias = "ads7846", \ + .max_speed_hz = 200000, \ + .irq = IRQ_NS9XXX_EXT3, \ + .bus_num = 0, \ + .chip_select = 0, \ + .platform_data = &ccx9c_touch_data, \ + }, + +#else +#define CCX9C_SPI_TOUCH +void __init ccx9c_add_device_touch(void) {} +#endif + +static struct spi_board_info spi_devices[] __initdata = { + CCX9C_SPI_TOUCH + /* Add here other SPI devices, if any... */ +}; + +static void __init mach_cc9cjs_init_machine(void) +{ + /* register several system clocks */ + ns9360_init_machine(); + + /* UARTs */ +#if defined(CONFIG_CCX9C_SERIAL_PORTA_RXTX) + ns9xxx_add_device_ccx9c_uarta_rxtx(); +#elif defined(CONFIG_CCX9C_SERIAL_PORTA_CTSRTSRXTX) + ns9xxx_add_device_ccx9c_uarta_ctsrtsrxtx(); +#elif defined(CONFIG_CCX9C_SERIAL_PORTA_FULL) + ns9xxx_add_device_ccx9c_uarta_full(); +#endif +#if defined(CONFIG_CCX9C_SERIAL_PORTB_RXTX) + ns9xxx_add_device_ccx9c_uartb_rxtx(); +#elif defined(CONFIG_CCX9C_SERIAL_PORTB_CTSRTSRXTX) + ns9xxx_add_device_ccx9c_uartb_ctsrtsrxtx(); +#elif defined(CONFIG_CCX9C_SERIAL_PORTB_FULL) + ns9xxx_add_device_ccx9c_uartb_full(); +#endif +#if defined(CONFIG_CCX9C_SERIAL_PORTC_RXTX) + ns9xxx_add_device_ccx9c_uartc_rxtx(); +#elif defined(CONFIG_CCX9C_SERIAL_PORTC_CTSRTSRXTX) + ns9xxx_add_device_ccx9c_uartc_ctsrtsrxtx(); +#elif defined(CONFIG_CCX9C_SERIAL_PORTC_FULL) + ns9xxx_add_device_ccx9c_uartc_full(); +#endif +#if defined(CONFIG_CCX9C_SERIAL_PORTD_RXTX) + ns9xxx_add_device_ccx9c_uartd_rxtx(); +#elif defined(CONFIG_CCX9C_SERIAL_PORTD_CTSRTSRXTX) + ns9xxx_add_device_ccx9c_uartd_ctsrtsrxtx(); +#elif defined(CONFIG_CCX9C_SERIAL_PORTD_FULL) + ns9xxx_add_device_ccx9c_uartd_full(); +#endif + + /* SPI */ +#if defined(CONFIG_CCX9C_SPI_PORTA) + ns9xxx_add_device_ccx9c_spi_porta(); +#endif +#if defined(CONFIG_CCX9C_SPI_PORTB) + ns9xxx_add_device_ccx9c_spi_portb(); +#endif +#if defined(CONFIG_CCX9C_SPI_PORTC) + ns9xxx_add_device_ccx9c_spi_portc(); +#endif +#if defined(CONFIG_CCX9C_SPI_PORTD) + ns9xxx_add_device_ccx9c_spi_portd(); +#endif + + /* Ethernet */ + ns9xxx_add_device_ccx9c_eth(); + + /* NAND flash */ + ns9xxx_add_device_ccx9c_nand(); + + /* Watchdog timer */ + ns9xxx_add_device_ns9360_wdt(); + + /* USB host */ + ns9xxx_add_device_ns9360_usbh(); + + /* I2C controller */ + ns9xxx_add_device_ccx9c_i2c(); + + /* I2C devices */ + i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices)); + + /* Framebuffer */ +#if defined(CONFIG_CCX9C_FB) + ns9xxx_add_device_ccx9c_fb(23); +#endif + + /* Touchscreen */ + ccx9c_add_device_touch(); + + /* SPI devices */ + spi_register_board_info(spi_devices, ARRAY_SIZE(spi_devices)); + + /* RTC */ + ns9xxx_add_device_ns9360_rtc(); +} + +MACHINE_START(CC9C, "ConnectCore 9C") + .map_io = ns9360_map_io, + .init_irq = ns9xxx_init_irq, + .init_machine = mach_cc9cjs_init_machine, + .timer = &ns9360_timer, + .boot_params = 0x100, +MACHINE_END diff --git a/arch/arm/mach-ns9xxx/mach-cc9p9215.c b/arch/arm/mach-ns9xxx/mach-cc9p9215.c new file mode 100644 index 000000000000..6e223e70078c --- /dev/null +++ b/arch/arm/mach-ns9xxx/mach-cc9p9215.c @@ -0,0 +1,23 @@ +/* + * arch/arm/mach-ns9xxx/mach-cc9p9215.c + * + * Copyright (C) 2007 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 <asm/mach/arch.h> +#include <asm/mach-types.h> + +#include "irq.h" +#include "processor-ns921x.h" + +MACHINE_START(CC9P9215, "ConnectCore 9P 9215") + .map_io = ns921x_map_io, + .init_irq = ns9xxx_init_irq, + .init_machine = ns921x_init_machine, + .timer = &ns921x_timer, + .boot_params = 0x100, +MACHINE_END diff --git a/arch/arm/mach-ns9xxx/mach-cc9p9215js.c b/arch/arm/mach-ns9xxx/mach-cc9p9215js.c new file mode 100644 index 000000000000..96f8220f0eec --- /dev/null +++ b/arch/arm/mach-ns9xxx/mach-cc9p9215js.c @@ -0,0 +1,192 @@ +/* + * arch/arm/mach-ns9xxx/mach-cc9p9215.c + * + * Copyright (C) 2007 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/i2c.h> +#include <linux/i2c/pca953x.h> +#include <linux/spi/spi.h> +#include <linux/spi/ads7846.h> +#include <linux/gpio.h> + +#include <asm/mach/arch.h> +#include <asm/mach-types.h> + +#include "irq.h" +#include "processor-ns921x.h" +#include "ns921x_devices.h" +#include "ns9215_devices.h" +#include "cc9p9215_devices.h" + +/* I2C devices */ +#if defined(CONFIG_GPIO_PCA953X) || defined(CONFIG_GPIO_PCA953X_MODULE) +static struct pca953x_platform_data pca9554_data = { + .gpio_base = 108, +}; +#endif + +static struct i2c_board_info i2c_devices[] __initdata = { +#if defined(CONFIG_GPIO_PCA953X) || defined(CONFIG_GPIO_PCA953X_MODULE) + { + I2C_BOARD_INFO("pca9554", 0x20), + .platform_data = &pca9554_data, + }, +#endif +}; + +#ifdef CONFIG_CC9P9215JS_TOUCH +static int touch_pendown_state(void) +{ + return gpio_get_value(101) ? 0 : 1; +} + +static struct ads7846_platform_data cc9p9215js_touch_data = { + .model = 7843, + .get_pendown_state = touch_pendown_state, + .x_min = 100, + .y_min = 100, + .x_max = 4000, + .y_max = 4000, + .rotate = 180, + .buflen = 20, + .skip_samples = 0, +}; + +void __init cc9p9215js_add_device_touch(void) +{ + if (gpio_request(101, "ads7846")) + return; + gpio_configure_ns921x(101, 0, 0, 2, 0); +} + +#define CC9P9215JS_TOUCH \ + { \ + .modalias = "ads7846", \ + .max_speed_hz = 300000, \ + .irq = IRQ_NS9XXX_EXT3, \ + .bus_num = 1, \ + .chip_select = 0, \ + .platform_data = &cc9p9215js_touch_data, \ + }, + +#else +#define CC9P9215JS_TOUCH +void __init cc9p9215js_add_device_touch(void) {} +#endif + +/* SPI devices */ +static struct spi_board_info spi_devices[] __initdata = { + CC9P9215JS_TOUCH +#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE) + { + .modalias = "spidev", + .max_speed_hz = 10000000, + .bus_num = 1, + .chip_select = 0, + }, +#endif +}; + +static void __init mach_cc9p9215js_init_machine(void) +{ + /* register several system clocks */ + ns921x_init_machine(); + + /* UARTs */ +#if defined(CONFIG_CC9P9215JS_SERIAL_PORTA_RXTX) + ns9xxx_add_device_cc9p9215_uarta_rxtx(); +#elif defined(CONFIG_CC9P9215JS_SERIAL_PORTA_CTSRTSRXTX) || \ + defined(CONFIG_CC9P9215JS_SERIAL_PORTA_RXTX485) + ns9xxx_add_device_cc9p9215_uarta_ctsrtsrxtx(); +#elif defined(CONFIG_CC9P9215JS_SERIAL_PORTA_FULL) + ns9xxx_add_device_cc9p9215_uarta_full(); +#endif +#if defined(CONFIG_CC9P9215JS_SERIAL_PORTB_RXTX) + ns9xxx_add_device_cc9p9215_uartb_rxtx(); +#elif defined(CONFIG_CC9P9215JS_SERIAL_PORTB_CTSRTSRXTX) || \ + defined(CONFIG_CC9P9215JS_SERIAL_PORTB_RXTX485) + ns9xxx_add_device_cc9p9215_uartb_ctsrtsrxtx(); +#elif defined(CONFIG_CC9P9215JS_SERIAL_PORTB_FULL) + ns9xxx_add_device_cc9p9215_uartb_full(); +#endif +#if defined(CONFIG_CC9P9215JS_SERIAL_PORTC_RXTX) + ns9xxx_add_device_cc9p9215_uartc_rxtx(); +#elif defined(CONFIG_CC9P9215JS_SERIAL_PORTC_CTSRTSRXTX) || \ + defined(CONFIG_CC9P9215JS_SERIAL_PORTC_RXTX485) + ns9xxx_add_device_cc9p9215_uartc_ctsrtsrxtx(); +#elif defined(CONFIG_CC9P9215JS_SERIAL_PORTC_FULL) + ns9xxx_add_device_cc9p9215_uartc_full(); +#endif +#if defined(CONFIG_CC9P9215JS_SERIAL_PORTD_RXTX) + ns9xxx_add_device_cc9p9215_uartd_rxtx(); +#elif defined(CONFIG_CC9P9215JS_SERIAL_PORTD_CTSRTSRXTX) || \ + defined(CONFIG_CC9P9215JS_SERIAL_PORTD_RXTX485) + ns9xxx_add_device_cc9p9215_uartd_ctsrtsrxtx(); +#elif defined(CONFIG_CC9P9215JS_SERIAL_PORTD_FULL) + ns9xxx_add_device_cc9p9215_uartd_full(); +#endif + + /* Ethernet */ + ns9xxx_add_device_cc9p9215_eth(); + + /* SPI */ +#ifdef CONFIG_CC9P9215JS_SPI + ns9xxx_add_device_cc9p9215_spi(); +#endif + + /* SPI devices */ + spi_register_board_info(spi_devices, ARRAY_SIZE(spi_devices)); + + /* Watchdog timer */ + ns9xxx_add_device_ns921x_wdt(); + + /* NOR Flash */ + ns9xxx_add_device_cc9p9215_flash(); + + /* I2C controller */ + ns9xxx_add_device_cc9p9215_i2c(); + + /* I2C devices */ + i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices)); + + /* Leds */ + ns9xxx_add_device_ns9215_leds(); + + /* Analog Digital Converter */ + ns9xxx_add_device_ns9215_adc(); + + /* AES HW Encryption module */ +#if defined(CONFIG_CRYPTO_DEV_NS921X_AES) || \ + defined(CONFIG_CRYPTO_DEV_NS921X_AES_MODULE) + ns9xxx_add_device_ns921x_aes(); +#endif + + /* Real Time Clock */ + ns9xxx_add_device_ns9215_rtc(); + + /* GPIO 4 is used as wake up gpio */ + (void)ns921x_extgpio_pm_wakeup_init(4); + + /* Init the FIM devices */ + ns9xxx_add_device_ns921x_fims(); + + /* Video */ + ns9xxx_add_device_cc9p9215_edt_diplay(); + + /* Touchscreen */ + cc9p9215js_add_device_touch(); +} + +MACHINE_START(CC9P9215JS, "ConnectCore 9P 9215 on a JSCC9P9215 Devboard") + .map_io = ns921x_map_io, + .init_irq = ns9xxx_init_irq, + .init_machine = mach_cc9p9215js_init_machine, + .timer = &ns921x_timer, + .boot_params = 0x100, +MACHINE_END diff --git a/arch/arm/mach-ns9xxx/mach-cc9p9360js.c b/arch/arm/mach-ns9xxx/mach-cc9p9360js.c index 729f68da4293..cebf99f49a84 100644 --- a/arch/arm/mach-ns9xxx/mach-cc9p9360js.c +++ b/arch/arm/mach-ns9xxx/mach-cc9p9360js.c @@ -1,28 +1,201 @@ /* * arch/arm/mach-ns9xxx/mach-cc9p9360js.c * - * Copyright (C) 2006,2007 by Digi International Inc. + * 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/i2c.h> +#include <linux/i2c/pca953x.h> +#include <linux/spi/spi.h> +#include <linux/spi/ads7846.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/irq.h> + #include <asm/mach/arch.h> #include <asm/mach-types.h> +#include <mach/irqs.h> + +#include "irq.h" +#include "processor-ns9360.h" +#include "ns9360_devices.h" +#include "cc9p9360_devices.h" + +/* I2C devices */ +#if defined(CONFIG_GPIO_PCA953X) || defined(CONFIG_GPIO_PCA953X_MODULE) +static struct pca953x_platform_data pca9554_data = { + .gpio_base = 108, +}; +#endif + +static struct i2c_board_info i2c_devices[] __initdata = { +#if defined(CONFIG_GPIO_PCA953X) || defined(CONFIG_GPIO_PCA953X_MODULE) + { + I2C_BOARD_INFO("pca9554", 0x20), + .platform_data = &pca9554_data, + }, +#endif +#if defined(CONFIG_RTC_DRV_DS1307) || defined(CONFIG_RTC_DRV_DS1307_MODULE) + { + I2C_BOARD_INFO("ds1337", 0x68), +#if defined(CONFIG_EXTERNAL_RTC_ALARM) + .irq = IRQ_NS9XXX_EXT0, +#endif + }, +#endif +}; + +#ifdef CONFIG_CC9P9360JS_TOUCH +static int touch_pendown_state(void) +{ + return gpio_get_value(69) ? 0 : 1; +} + +static struct ads7846_platform_data cc9p9360js_touch_data = { + .model = 7843, + .get_pendown_state = touch_pendown_state, + .x_min = 100, + .y_min = 100, + .x_max = 4000, + .y_max = 4000, + .rotate = 180, + .buflen = 20, + .skip_samples = 0, +}; + +void __init cc9p9360js_add_device_touch(void) +{ + if (gpio_request(69, "ads7846")) + return; + + gpio_configure_ns9360(69, 0, 0, 2); +} + +#define CC9P9360JS_TOUCH \ + { \ + .modalias = "ads7846", \ + .max_speed_hz = 200000, \ + .irq = IRQ_NS9XXX_EXT1, \ + .bus_num = 0, \ + .chip_select = 0, \ + .platform_data = &cc9p9360js_touch_data, \ + }, + +#else +#define CC9P9360JS_TOUCH +void __init cc9p9360js_add_device_touch(void) {} +#endif -#include <mach/processor-ns9360.h> +static struct spi_board_info spi_devices[] __initdata = { + CC9P9360JS_TOUCH + /* Add here other SPI devices, if any... */ +}; -#include "board-jscc9p9360.h" -#include "generic.h" +#if defined(CONFIG_EXTERNAL_RTC_ALARM) +void __init cc9p9360js_external_rtc_alarm(void) +{ + /* Request and configure GPIO */ + if (gpio_request(13, "ds1337")) + return; + gpio_configure_ns9360(13, 0, 0, 1); + /* Configure interrupt */ + set_irq_type( IRQ_NS9XXX_EXT0, IRQF_TRIGGER_FALLING ); +} +#endif static void __init mach_cc9p9360js_init_machine(void) { - ns9xxx_init_machine(); - board_jscc9p9360_init_machine(); + /* register several system clocks */ + ns9360_init_machine(); + + /* UARTs */ +#if defined(CONFIG_CC9P9360JS_SERIAL_PORTA_RXTX) + ns9xxx_add_device_cc9p9360_uarta_rxtx(); +#elif defined(CONFIG_CC9P9360JS_SERIAL_PORTA_CTSRTSRXTX) + ns9xxx_add_device_cc9p9360_uarta_ctsrtsrxtx(); +#elif defined(CONFIG_CC9P9360JS_SERIAL_PORTA_FULL) + ns9xxx_add_device_cc9p9360_uarta_full(); +#endif +#if defined(CONFIG_CC9P9360JS_SERIAL_PORTB_RXTX) + ns9xxx_add_device_cc9p9360_uartb_rxtx(); +#elif defined(CONFIG_CC9P9360JS_SERIAL_PORTB_CTSRTSRXTX) + ns9xxx_add_device_cc9p9360_uartb_ctsrtsrxtx(); +#elif defined(CONFIG_CC9P9360JS_SERIAL_PORTB_FULL) + ns9xxx_add_device_cc9p9360_uartb_full(); +#endif +#if defined(CONFIG_CC9P9360JS_SERIAL_PORTC_RXTX) + ns9xxx_add_device_cc9p9360_uartc_rxtx(); +#elif defined(CONFIG_CC9P9360JS_SERIAL_PORTC_CTSRTSRXTX) + ns9xxx_add_device_cc9p9360_uartc_ctsrtsrxtx(); +#elif defined(CONFIG_CC9P9360JS_SERIAL_PORTC_FULL) + ns9xxx_add_device_cc9p9360_uartc_full(); +#endif +#if defined(CONFIG_CC9P9360JS_SERIAL_PORTD_RXTX) + ns9xxx_add_device_cc9p9360_uartd_rxtx(); +#elif defined(CONFIG_CC9P9360JS_SERIAL_PORTD_CTSRTSRXTX) + ns9xxx_add_device_cc9p9360_uartd_ctsrtsrxtx(); +#elif defined(CONFIG_CC9P9360JS_SERIAL_PORTD_FULL) + ns9xxx_add_device_cc9p9360_uartd_full(); +#endif + + /* SPI */ +#if defined(CONFIG_CC9P9360JS_SPI_PORTA) + ns9xxx_add_device_cc9p9360_spi_porta(); +#endif +#if defined(CONFIG_CC9P9360JS_SPI_PORTB) + ns9xxx_add_device_cc9p9360_spi_portb(); +#endif +#if defined(CONFIG_CC9P9360JS_SPI_PORTC) + ns9xxx_add_device_cc9p9360_spi_portc(); +#endif +#if defined(CONFIG_CC9P9360JS_SPI_PORTD) + ns9xxx_add_device_cc9p9360_spi_portd(); +#endif + + /* Ethernet */ + ns9xxx_add_device_cc9p9360_eth(); + + /* NAND flash */ + ns9xxx_add_device_cc9p9360_nand(); + + /* Watchdog timer */ + ns9xxx_add_device_ns9360_wdt(); + + /* USB host */ + ns9xxx_add_device_ns9360_usbh(); + + /* I2C controller */ + ns9xxx_add_device_cc9p9360_i2c(); + + /* I2C devices */ + i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices)); + + /* Framebuffer */ +#if defined(CONFIG_CC9P9360JS_FB) + ns9xxx_add_device_cc9p9360_fb(18); +#endif + + /* Touchscreen */ + cc9p9360js_add_device_touch(); + + /* SPI devices */ + spi_register_board_info(spi_devices, ARRAY_SIZE(spi_devices)); + + /* RTC (internal) */ + ns9xxx_add_device_ns9360_rtc(); + + /* RTC (external) */ +#if defined(CONFIG_EXTERNAL_RTC_ALARM) + cc9p9360js_external_rtc_alarm(); +#endif } -MACHINE_START(CC9P9360JS, "Digi ConnectCore 9P 9360 on an JSCC9P9360 Devboard") +MACHINE_START(CC9P9360JS, "ConnectCore 9P 9360 on a JSCC9P9360 Devboard") .map_io = ns9360_map_io, .init_irq = ns9xxx_init_irq, .init_machine = mach_cc9p9360js_init_machine, diff --git a/arch/arm/mach-ns9xxx/mach-ccw9c.c b/arch/arm/mach-ns9xxx/mach-ccw9c.c new file mode 100644 index 000000000000..3bb098c92b1e --- /dev/null +++ b/arch/arm/mach-ns9xxx/mach-ccw9c.c @@ -0,0 +1,176 @@ +/* + * arch/arm/mach-ns9xxx/mach-ccw9c.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/i2c.h> +#include <linux/i2c/pca953x.h> +#include <linux/spi/spi.h> +#include <linux/spi/ads7846.h> +#include <linux/gpio.h> + +#include <asm/mach/arch.h> +#include <asm/mach-types.h> + +#include "irq.h" +#include "processor-ns9360.h" +#include "ns9360_devices.h" +#include "ccx9c_devices.h" + +/* I2C devices */ +#if defined(CONFIG_GPIO_PCA953X) || defined(CONFIG_GPIO_PCA953X_MODULE) +static struct pca953x_platform_data pca9554_data = { + .gpio_base = 108, +}; +#endif + +static struct i2c_board_info i2c_devices[] __initdata = { +#if defined(CONFIG_GPIO_PCA953X) || defined(CONFIG_GPIO_PCA953X_MODULE) + { + I2C_BOARD_INFO("pca9554", 0x20), + .platform_data = &pca9554_data, + }, +#endif +}; + +#ifdef CONFIG_CCX9C_TOUCH +static int touch_pendown_state(void) +{ + return gpio_get_value(18) ? 0 : 1; +} + +static struct ads7846_platform_data ccx9c_touch_data = { + .model = 7843, + .get_pendown_state = touch_pendown_state, + .x_min = 100, + .y_min = 100, + .x_max = 4000, + .y_max = 4000, + .rotate = 180, + .buflen = 20, + .skip_samples = 0, +}; + +void __init ccx9c_add_device_touch(void) +{ + if (gpio_request(18, "ads7846")) + return; + + gpio_configure_ns9360(18, 0, 0, 2); +} + +#define CCX9C_SPI_TOUCH \ + { \ + .modalias = "ads7846", \ + .max_speed_hz = 200000, \ + .irq = IRQ_NS9XXX_EXT3, \ + .bus_num = 0, \ + .chip_select = 0, \ + .platform_data = &ccx9c_touch_data, \ + }, + +#else +#define CCX9C_SPI_TOUCH +void __init ccx9c_add_device_touch(void) {} +#endif + +static struct spi_board_info spi_devices[] __initdata = { + CCX9C_SPI_TOUCH + /* Add here other SPI devices, if any... */ +}; + +static void __init mach_ccw9cjs_init_machine(void) +{ + /* register several system clocks */ + ns9360_init_machine(); + + /* UARTs */ +#if defined(CONFIG_CCX9C_SERIAL_PORTA_RXTX) + ns9xxx_add_device_ccx9c_uarta_rxtx(); +#elif defined(CONFIG_CCX9C_SERIAL_PORTA_CTSRTSRXTX) + ns9xxx_add_device_ccx9c_uarta_ctsrtsrxtx(); +#elif defined(CONFIG_CCX9C_SERIAL_PORTA_FULL) + ns9xxx_add_device_ccx9c_uarta_full(); +#endif +#if defined(CONFIG_CCX9C_SERIAL_PORTB_RXTX) + ns9xxx_add_device_ccx9c_uartb_rxtx(); +#elif defined(CONFIG_CCX9C_SERIAL_PORTB_CTSRTSRXTX) + ns9xxx_add_device_ccx9c_uartb_ctsrtsrxtx(); +#elif defined(CONFIG_CCX9C_SERIAL_PORTB_FULL) + ns9xxx_add_device_ccx9c_uartb_full(); +#endif +#if defined(CONFIG_CCX9C_SERIAL_PORTC_RXTX) + ns9xxx_add_device_ccx9c_uartc_rxtx(); +#elif defined(CONFIG_CCX9C_SERIAL_PORTC_CTSRTSRXTX) + ns9xxx_add_device_ccx9c_uartc_ctsrtsrxtx(); +#elif defined(CONFIG_CCX9C_SERIAL_PORTC_FULL) + ns9xxx_add_device_ccx9c_uartc_full(); +#endif +#if defined(CONFIG_CCX9C_SERIAL_PORTD_RXTX) + ns9xxx_add_device_ccx9c_uartd_rxtx(); +#elif defined(CONFIG_CCX9C_SERIAL_PORTD_CTSRTSRXTX) + ns9xxx_add_device_ccx9c_uartd_ctsrtsrxtx(); +#elif defined(CONFIG_CCX9C_SERIAL_PORTD_FULL) + ns9xxx_add_device_ccx9c_uartd_full(); +#endif + + /* SPI */ +#if defined(CONFIG_CCX9C_SPI_PORTA) + ns9xxx_add_device_ccx9c_spi_porta(); +#endif +#if defined(CONFIG_CCX9C_SPI_PORTB) + ns9xxx_add_device_ccx9c_spi_portb(); +#endif +#if defined(CONFIG_CCX9C_SPI_PORTC) + ns9xxx_add_device_ccx9c_spi_portc(); +#endif +#if defined(CONFIG_CCX9C_SPI_PORTD) + ns9xxx_add_device_ccx9c_spi_portd(); +#endif + + /* Ethernet */ + ns9xxx_add_device_ccx9c_eth(); + + /* NAND flash */ + ns9xxx_add_device_ccx9c_nand(); + + /* Watchdog timer */ + ns9xxx_add_device_ns9360_wdt(); + + /* USB host */ + ns9xxx_add_device_ns9360_usbh(); + + /* I2C controller */ + ns9xxx_add_device_ccx9c_i2c(); + + /* I2C devices */ + i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices)); + + /* Framebuffer */ +#if defined(CONFIG_CCX9C_FB) + ns9xxx_add_device_ccx9c_fb(23); +#endif + + /* Touchscreen */ + ccx9c_add_device_touch(); + + /* SPI devices */ + spi_register_board_info(spi_devices, ARRAY_SIZE(spi_devices)); + + /* RTC */ + ns9xxx_add_device_ns9360_rtc(); +} + +MACHINE_START(CCW9C, "ConnectCore Wi-9C") + .map_io = ns9360_map_io, + .init_irq = ns9xxx_init_irq, + .init_machine = mach_ccw9cjs_init_machine, + .timer = &ns9360_timer, + .boot_params = 0x100, +MACHINE_END diff --git a/arch/arm/mach-ns9xxx/mach-ccw9p9215.c b/arch/arm/mach-ns9xxx/mach-ccw9p9215.c new file mode 100644 index 000000000000..db86575a120e --- /dev/null +++ b/arch/arm/mach-ns9xxx/mach-ccw9p9215.c @@ -0,0 +1,23 @@ +/* + * arch/arm/mach-ns9xxx/mach-cc9p9215.c + * + * Copyright (C) 2007 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 <asm/mach/arch.h> +#include <asm/mach-types.h> + +#include "irq.h" +#include "processor-ns921x.h" + +MACHINE_START(CCW9P9215, "ConnectCore Wi-9P 9215") + .map_io = ns921x_map_io, + .init_irq = ns9xxx_init_irq, + .init_machine = ns921x_init_machine, + .timer = &ns921x_timer, + .boot_params = 0x100, +MACHINE_END diff --git a/arch/arm/mach-ns9xxx/mach-ccw9p9215js.c b/arch/arm/mach-ns9xxx/mach-ccw9p9215js.c new file mode 100644 index 000000000000..4a5ddcb33dd8 --- /dev/null +++ b/arch/arm/mach-ns9xxx/mach-ccw9p9215js.c @@ -0,0 +1,242 @@ +/* + * arch/arm/mach-ns9xxx/mach-cc9p9215.c + * + * Copyright (C) 2007 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/i2c.h> +#include <linux/i2c/pca953x.h> +#include <linux/spi/spi.h> +#include <linux/spi/ads7846.h> +#include <linux/gpio.h> +#include <linux/crc32.h> + +#include <asm/mach/arch.h> +#include <asm/mach-types.h> +#include <asm/leds.h> + +#include "irq.h" +#include "pipermain.h" +#include "processor-ns921x.h" +#include "ns921x_devices.h" +#include "ns9215_devices.h" +#include "cc9p9215_devices.h" +#include "ccw9p9215_devices.h" + + +/* I2C devices */ +#if defined(CONFIG_GPIO_PCA953X) || defined(CONFIG_GPIO_PCA953X_MODULE) +static struct pca953x_platform_data pca9554_data = { + .gpio_base = 108, +}; +#endif + +static struct i2c_board_info i2c_devices[] __initdata = { +#if defined(CONFIG_GPIO_PCA953X) || defined(CONFIG_GPIO_PCA953X_MODULE) + { + I2C_BOARD_INFO("pca9554", 0x20), + .platform_data = &pca9554_data, + }, +#endif +}; + +#ifdef CONFIG_CC9P9215JS_TOUCH +static int touch_pendown_state(void) +{ + return gpio_get_value(101) ? 0 : 1; +} + +static struct ads7846_platform_data cc9p9215js_touch_data = { + .model = 7843, + .get_pendown_state = touch_pendown_state, + .x_min = 100, + .y_min = 100, + .x_max = 4000, + .y_max = 4000, + .rotate = 180, + .buflen = 20, + .skip_samples = 0, +}; + +void __init cc9p9215js_add_device_touch(void) +{ + if (gpio_request(101, "ads7846")) + return; + gpio_configure_ns921x(101, 0, 0, 2, 0); +} + +#define CC9P9215JS_TOUCH \ + { \ + .modalias = "ads7846", \ + .max_speed_hz = 300000, \ + .irq = IRQ_NS9XXX_EXT3, \ + .bus_num = 1, \ + .chip_select = 0, \ + .platform_data = &cc9p9215js_touch_data, \ + }, + +#else +#define CC9P9215JS_TOUCH +void __init cc9p9215js_add_device_touch(void) {} +#endif + +/* SPI devices */ +static struct spi_board_info spi_devices[] __initdata = { +#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE) + { + .modalias = "spidev", + .max_speed_hz = 10000000, + .bus_num = 1, + .chip_select = 0, + }, +#endif + CC9P9215JS_TOUCH +}; + + +#if defined(CONFIG_DIGI_PIPER_WIFI) +static struct piper_pdata ccw9p9215_piper_pdata = { + .rst_gpio = 92, + .irq_gpio = 104, + .i2c_adapter_num = 0, +}; + +static void __init ccw9p9215js_fixup(struct machine_desc *desc, + struct tag *tags, char **cmdline, + struct meminfo *mi) +{ + unsigned char *mac = phys_to_virt(desc->boot_params) + 0xf00; + wcd_data_t *pwcal; + u32 crc; + + /* 8 bytes after the mac address, its located the calibration data */ + pwcal = (wcd_data_t *)(mac + 8); + memcpy(&ccw9p9215_piper_pdata.macaddr[0], mac, 6); + + if (!strncmp(pwcal->header.magic_string, WCD_MAGIC, + sizeof(pwcal->header.magic_string))) { + /* check version */ + if (((pwcal->header.ver_major >= '1') && (pwcal->header.ver_major <= '9')) && + ((pwcal->header.ver_minor >= '0') && (pwcal->header.ver_minor <= '9'))) { + crc = ~crc32_le(~0, (unsigned char const *)pwcal->cal_curves_bg, + pwcal->header.wcd_len); + if (crc == pwcal->header.wcd_crc) { + memcpy(&ccw9p9215_piper_pdata.wcd, pwcal, sizeof(wcd_data_t)); + return; + } + } + } + + memset(&ccw9p9215_piper_pdata.wcd, 0, sizeof(wcd_data_t)); +} +#endif + +static void __init mach_ccw9p9215js_init_machine(void) +{ + /* register several system clocks */ + ns921x_init_machine(); + + /* UARTs */ +#if defined(CONFIG_CC9P9215JS_SERIAL_PORTA_RXTX) + ns9xxx_add_device_cc9p9215_uarta_rxtx(); +#elif defined(CONFIG_CC9P9215JS_SERIAL_PORTA_CTSRTSRXTX) || \ + defined(CONFIG_CC9P9215JS_SERIAL_PORTA_RXTX485) + ns9xxx_add_device_cc9p9215_uarta_ctsrtsrxtx(); +#elif defined(CONFIG_CC9P9215JS_SERIAL_PORTA_FULL) + ns9xxx_add_device_cc9p9215_uarta_full(); +#endif +#if defined(CONFIG_CC9P9215JS_SERIAL_PORTB_RXTX) + ns9xxx_add_device_cc9p9215_uartb_rxtx(); +#elif defined(CONFIG_CC9P9215JS_SERIAL_PORTB_CTSRTSRXTX) || \ + defined(CONFIG_CC9P9215JS_SERIAL_PORTB_RXTX485) + ns9xxx_add_device_cc9p9215_uartb_ctsrtsrxtx(); +#elif defined(CONFIG_CC9P9215JS_SERIAL_PORTB_FULL) + ns9xxx_add_device_cc9p9215_uartb_full(); +#endif +#if defined(CONFIG_CC9P9215JS_SERIAL_PORTC_RXTX) + ns9xxx_add_device_cc9p9215_uartc_rxtx(); +#elif defined(CONFIG_CC9P9215JS_SERIAL_PORTC_CTSRTSRXTX) || \ + defined(CONFIG_CC9P9215JS_SERIAL_PORTC_RXTX485) + ns9xxx_add_device_cc9p9215_uartc_ctsrtsrxtx(); +#elif defined(CONFIG_CC9P9215JS_SERIAL_PORTC_FULL) + ns9xxx_add_device_cc9p9215_uartc_full(); +#endif +#if defined(CONFIG_CC9P9215JS_SERIAL_PORTD_RXTX) + ns9xxx_add_device_cc9p9215_uartd_rxtx(); +#elif defined(CONFIG_CC9P9215JS_SERIAL_PORTD_CTSRTSRXTX) || \ + defined(CONFIG_CC9P9215JS_SERIAL_PORTD_RXTX485) + ns9xxx_add_device_cc9p9215_uartd_ctsrtsrxtx(); +#elif defined(CONFIG_CC9P9215JS_SERIAL_PORTD_FULL) + ns9xxx_add_device_cc9p9215_uartd_full(); +#endif + + /* Ethernet */ + ns9xxx_add_device_cc9p9215_eth(); + + /* 802.11 */ +#if defined(CONFIG_DIGI_PIPER_WIFI) + ns9xxx_add_device_ccw9p9215_wifi(&ccw9p9215_piper_pdata); +#endif + + /* SPI */ +#ifdef CONFIG_CC9P9215JS_SPI + ns9xxx_add_device_cc9p9215_spi(); +#endif + + /* SPI devices */ + spi_register_board_info(spi_devices, ARRAY_SIZE(spi_devices)); + + /* Watchdog timer */ + ns9xxx_add_device_ns921x_wdt(); + + /* NOR Flash */ + ns9xxx_add_device_cc9p9215_flash(); + + /* I2C controller */ + ns9xxx_add_device_cc9p9215_i2c(); + + /* I2C devices */ + i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices)); + + /* Leds */ + ns9xxx_add_device_ns9215_leds(); + + /* Analog Digital Converter */ + ns9xxx_add_device_ns9215_adc(); + + /* AES HW Encryption module */ +#if defined(CONFIG_CRYPTO_DEV_NS921X_AES) || \ + defined(CONFIG_CRYPTO_DEV_NS921X_AES_MODULE) + ns9xxx_add_device_ns921x_aes(); +#endif + + /* Real Time Clock */ + ns9xxx_add_device_ns9215_rtc(); + + /* GPIO 4 is used as wake up gpio */ + (void)ns921x_extgpio_pm_wakeup_init(4); + + /* Init the FIM devices */ + ns9xxx_add_device_ns921x_fims(); + + /* Video */ + ns9xxx_add_device_cc9p9215_edt_diplay(); + + /* Touchscreen */ + cc9p9215js_add_device_touch(); +} +MACHINE_START(CCW9P9215JS, "ConnectCore Wi-9P 9215 on a JSCCW9P9215 Devboard") + .map_io = ns921x_map_io, + .init_irq = ns9xxx_init_irq, +#if defined(CONFIG_DIGI_PIPER_WIFI) + .fixup = ccw9p9215js_fixup, +#endif + .init_machine = mach_ccw9p9215js_init_machine, + .timer = &ns921x_timer, + .boot_params = 0x100, +MACHINE_END diff --git a/arch/arm/mach-ns9xxx/mach-cme9210.c b/arch/arm/mach-ns9xxx/mach-cme9210.c new file mode 100644 index 000000000000..29f71ce0acf1 --- /dev/null +++ b/arch/arm/mach-ns9xxx/mach-cme9210.c @@ -0,0 +1,24 @@ +/* + * arch/arm/mach-ns9xxx/mach-cme9210.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 <asm/mach/arch.h> +#include <asm/mach-types.h> + +#include "irq.h" +#include "processor-ns921x.h" + +MACHINE_START(CME9210JS, "Digi Connect ME 9210") + .map_io = ns921x_map_io, + .init_irq = ns9xxx_init_irq, + .init_machine = ns921x_init_machine, + .timer = &ns921x_timer, + .boot_params = 0x100, +MACHINE_END diff --git a/arch/arm/mach-ns9xxx/mach-cme9210js.c b/arch/arm/mach-ns9xxx/mach-cme9210js.c new file mode 100644 index 000000000000..23853f86a778 --- /dev/null +++ b/arch/arm/mach-ns9xxx/mach-cme9210js.c @@ -0,0 +1,109 @@ +/* + * arch/arm/mach-ns9xxx/mach-cme9210js.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/platform_device.h> +#include <linux/netdevice.h> +#include <linux/spi/spi.h> + +#include <asm/mach/arch.h> +#include <asm/mach-types.h> + +#include "irq.h" +#include "processor-ns921x.h" +#include "ns921x_devices.h" +#include "cme9210_devices.h" + +/* SPI devices */ +static struct spi_board_info spi_devices[] __initdata = { +#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE) + { + .modalias = "spidev", + .max_speed_hz = 10000000, + .bus_num = 1, + .chip_select = 0, + }, +#endif +}; + +/* I2C devices */ +/* Array to add I2C devices +static struct i2c_board_info i2c_devices[] __initdata = { + { + I2C_BOARD_INFO("device_name", address), + }, +}; +*/ + +static void __init mach_cme9210js_init_machine(void) +{ + /* register several system clocks */ + ns921x_init_machine(); + + /* UART */ +#if defined(CONFIG_CME9210JS_SERIAL_PORTA_RXTX) + ns9xxx_add_device_cme9210_uarta_rxtx(); +#elif defined(CONFIG_CME9210JS_SERIAL_PORTA_CTSRTSRXTX) || \ + defined(CONFIG_CME9210JS_SERIAL_PORTA_RXTX485) + ns9xxx_add_device_cme9210_uarta_ctsrtsrxtx(); +#elif defined(CONFIG_CME9210JS_SERIAL_PORTA_FULL) + ns9xxx_add_device_cme9210_uarta_full(); +#endif +#if defined(CONFIG_CME9210JS_SERIAL_PORTC_RXTX) + ns9xxx_add_device_cme9210_uartc_rxtx(); +#endif + + /* Ethernet */ + /* Adjust the netdev_max_backlog to a lower value. A big queue + * of incoming packets in the kernel can exhaust the kernel memory + * and trigger the OOM killer. This value can be tuned later in + * user space throught proc fs and with sysctl */ + netdev_max_backlog = 300; + ns9xxx_add_device_cme9210_eth(); + + /* Watchdog timer */ + ns9xxx_add_device_ns921x_wdt(); + + /* NOR Flash */ + ns9xxx_add_device_cme9210_flash(); + + /* SPI */ +#ifdef CONFIG_CME9210JS_SPI + ns9xxx_add_device_cme9210_spi(); +#endif + + /* SPI devices */ + spi_register_board_info(spi_devices, ARRAY_SIZE(spi_devices)); + + /* I2C controller */ + ns9xxx_add_device_cme9210_i2c(); + + /* I2C devices */ + /* + i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices)); + */ + + /* Init the FIM devices */ + ns9xxx_add_device_ns921x_fims(); + + /* AES HW Encryption module */ +#if defined(CONFIG_CRYPTO_DEV_NS921X_AES) || \ + defined(CONFIG_CRYPTO_DEV_NS921X_AES_MODULE) + ns9xxx_add_device_ns921x_aes(); +#endif +} + +MACHINE_START(CME9210JS, "Digi Connect ME 9210 on Devboard") + .map_io = ns921x_map_io, + .init_irq = ns9xxx_init_irq, + .init_machine = mach_cme9210js_init_machine, + .timer = &ns921x_timer, + .boot_params = 0x100, +MACHINE_END diff --git a/arch/arm/mach-ns9xxx/mach-inc20otter.c b/arch/arm/mach-ns9xxx/mach-inc20otter.c new file mode 100644 index 000000000000..477553fe4411 --- /dev/null +++ b/arch/arm/mach-ns9xxx/mach-inc20otter.c @@ -0,0 +1,23 @@ +/* + * arch/arm/mach-ns9xxx/mach-inc20otter.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 <asm/mach/arch.h> +#include <asm/mach-types.h> + +#include "irq.h" +#include "processor-ns921x.h" + +MACHINE_START(INC20OTTER, "Inc20-Otter") + .map_io = ns921x_map_io, + .init_irq = ns9xxx_init_irq, + .init_machine = ns921x_init_machine, + .timer = &ns921x_timer, + .boot_params = 0x100, +MACHINE_END diff --git a/arch/arm/mach-ns9xxx/mach-otter.c b/arch/arm/mach-ns9xxx/mach-otter.c new file mode 100644 index 000000000000..5ab5cf13e0d2 --- /dev/null +++ b/arch/arm/mach-ns9xxx/mach-otter.c @@ -0,0 +1,23 @@ +/* + * arch/arm/mach-ns9xxx/mach-otter.c + * + * Copyright (C) 2007 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 <asm/mach/arch.h> +#include <asm/mach-types.h> + +#include "irq.h" +#include "processor-ns921x.h" + +MACHINE_START(OTTER, "Otter") + .map_io = ns921x_map_io, + .init_irq = ns9xxx_init_irq, + .init_machine = ns921x_init_machine, + .timer = &ns921x_timer, + .boot_params = 0x100, +MACHINE_END diff --git a/arch/arm/mach-ns9xxx/ns9215_devices.c b/arch/arm/mach-ns9xxx/ns9215_devices.c new file mode 100644 index 000000000000..0a6f473b68f1 --- /dev/null +++ b/arch/arm/mach-ns9xxx/ns9215_devices.c @@ -0,0 +1,299 @@ +/* + * arch/arm/mach-ns9xxx/ns9215_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/interrupt.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/delay.h> + +#include <mach/ns9xxx-pwm.h> +#include <linux/leds.h> +#include <linux/io.h> +#include <linux/pwm.h> +#include <linux/pwm-led.h> + +#include <mach/hardware.h> +#include <mach/regs-sys-ns921x.h> + +#include "clock.h" +#include "processor-ns921x.h" + +#if defined(CONFIG_ARCH_NS9XXX) +static struct led_info ns9xxx_leds_pdata_info = { + .name = "leds-pwm", + .default_trigger = "ledtrig-dim", + .flags = 0, +}; + +static struct pwm_channel_config ns9xxx_leds_pdata_config = { + .duty_ns = 0, + .period_ns = 0, + +}; + +static struct pwm_led_platform_data ns9xxx_leds_pdata = { + .bus_id = "ns9xxx_pwmc.0", + .chan = 0, + .led_info = &ns9xxx_leds_pdata_info, + .config = &ns9xxx_leds_pdata_config, +}; + +static struct platform_device ns9xxx_device_ns9215_leds = { + .name = "leds-pwm", + .id = 0, + .dev = { + .platform_data = &ns9xxx_leds_pdata, + } +}; + +static struct ns9xxx_pwm_channel ns9215_pwm_channels[] = { + [0] = { + .timer = 6, + .gpio = 5, + }, + [1] = { + .timer = 7, + .gpio = 7, + }, + [2] = { + .timer = 8, + .gpio = 8, + }, + [3] = { + .timer = 9, + .gpio = 13, + } +}; + + +/* This structure will be initialized in the init function (see below) */ +static struct ns9xxx_pwm_pdata ns9215_pwm_pdata; + + +static struct platform_device ns9xxx_device_ns9215_pwm = { + .name = "ns9xxx_pwmc", + .id = 0, + .dev = { + .platform_data = &ns9215_pwm_pdata, + } +}; + +void __init ns9xxx_add_device_ns9215_leds(void) +{ + platform_device_register(&ns9xxx_device_ns9215_leds); + +#if 1 /* Enabled PWM by the user configuration */ + ns9215_pwm_pdata.channels = ns9215_pwm_channels; + ns9215_pwm_pdata.number_channels = ARRAY_SIZE(ns9215_pwm_channels); + platform_device_register(&ns9xxx_device_ns9215_pwm); +#endif + +} +#else +void __init ns9xxx_add_device_ns9215_leds(void) {} +#endif + +#if defined(CONFIG_ADC_NS9215) || defined(CONFIG_ADC_NS9215_MODULE) +static struct ns921x_sysclk adc_clk = { + .clk = { + .name = "adc-ns9215", + .id = -1, + .owner = THIS_MODULE, + }, + .mask = SYS_CLOCK_ADC, +}; + +static struct resource adc_resources[] = { + { + .start = 0x90039000, + .end = 0x90039027, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device ns9xxx_device_ns9215_adc = { + .name = "adc-ns9215", + .id = -1, + .resource = adc_resources, + .num_resources = ARRAY_SIZE(adc_resources), +}; + +void __init ns9xxx_add_device_ns9215_adc(void) +{ + if (clk_register(&adc_clk.clk)) + return; + + platform_device_register(&ns9xxx_device_ns9215_adc); +} +#else +void __init ns9xxx_add_device_ns9215_adc(void) {} +#endif + +#if defined(CONFIG_RTC_DRV_NS9XXX) || defined(CONFIG_RTC_DRV_NS9XXX_MODULE) +static irqreturn_t ns9xxx_plat_rtc_irq(int irq, void *data) +{ + u32 sysrtcmc = __raw_readl(SYS_RTCMC); + + if (sysrtcmc & SYS_RTCMC_RIS) { + REGSETIM(sysrtcmc, SYS_RTCMC, RIC, 1); + __raw_writel(sysrtcmc, SYS_RTCMC); + REGSETIM(sysrtcmc, SYS_RTCMC, RIC, 0); + __raw_writel(sysrtcmc, SYS_RTCMC); + + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static inline int wait_for_clkrdy(void) +{ + u32 sysrtcmc; + unsigned int timeout = 0x20; + +wait: + sysrtcmc = __raw_readl(SYS_RTCMC); + if (!(sysrtcmc & SYS_RTCMC_RIS)) { + if (unlikely(!--timeout)) + return -ETIMEDOUT; + udelay(1); + goto wait; + } + pr_debug("%s: SYS_RTCMC = 0x%x\n", __func__, sysrtcmc); + + REGSETIM(sysrtcmc, SYS_RTCMC, RIC, 1); + __raw_writel(sysrtcmc, SYS_RTCMC); + REGSETIM(sysrtcmc, SYS_RTCMC, RIC, 0); + __raw_writel(sysrtcmc, SYS_RTCMC); + + return sysrtcmc & SYS_RTCMC_SS ? 0 : -EIO; +} + +static int ns9215_rtc_endisable(struct clk *clk, int enable) +{ + u32 sysrtcmc = __raw_readl(SYS_RTCMC); + + pr_debug("%s: enable=%d, SYS_RTCMC=%08x\n", __func__, enable, sysrtcmc); + + if (enable && (sysrtcmc & (SYS_RTCMC_SS | SYS_RTCMC_MODE)) == + SYS_RTCMC_SS) { + /* the clock was disabled but is still active */ + + unsigned int timeout = 0x20; + + pr_debug("%s: wait until disabled clock becomes inactive\n", + __func__); +wait: + sysrtcmc = __raw_readl(SYS_RTCMC); + if (sysrtcmc & SYS_RTCMC_SS) { + if (unlikely(!--timeout)) + return -ETIMEDOUT; + udelay(1); + goto wait; + } + } + + if (enable && (sysrtcmc & SYS_RTCMC_SS)) { + pr_debug("%s: RTC clock already on\n", __func__); + return 0; + } + + if (enable) { + int ret; + + /* disable rtc irq because the irq is acked in wait_for_clkrdy + * and this might stuck the irq controller. (It doesn't like an + * irq to become active and then inactive before it is serviced. + * + * Not acking doesn't do the trick. Then the following might + * happen in an endless loop: + * - clk_enable + clk_disable with irqs off. This makes + * IRQ_NS9215_RTC pending. + * - reenable irqs + * - service IRQ_NS9215_RTC + * - platform handler runs and acks irq. + * - driver handler enables clk, sees that there is nothing to + * do, and disables clk again. All this with IRQ_NS9215_RTC + * being masked. + */ + disable_irq(IRQ_NS9215_RTC); + + __raw_writel(SYS_RTCMC_MODE_NORMAL, SYS_RTCMC); + + ret = wait_for_clkrdy(); + + enable_irq(IRQ_NS9215_RTC); + + return ret; + } else { + __raw_writel(SYS_RTCMC_MODE_STANDBY, SYS_RTCMC); + sysrtcmc = __raw_readl(SYS_RTCMC); + pr_debug("%s: disable done, SYS_RTCMC=%08x\n", + __func__, sysrtcmc); + + return 0; + } +} + +static struct ns921x_sysclk rtc_pm_clk = { + .clk = { + .name = "rtc-ns9xxx-pm", + .id = -1, + .owner = THIS_MODULE, + .endisable = ns921x_endisable_sysclock, + }, + .mask = SYS_CLOCK_RTC, + }; + +static struct clk rtc_clk = { + .name = "rtc-ns9xxx", + .id = 0, + .owner = THIS_MODULE, + .endisable = ns9215_rtc_endisable, +}; + +static struct resource rtc_resources[] = { + { + .start = 0x90060000, + .end = 0x900600ff, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_NS9215_RTC, + .flags = IORESOURCE_IRQ, + } +}; + +static struct platform_device ns9xxx_device_ns9215_rtc = { + .name = "rtc-ns9xxx", + .id = 0, + .resource = rtc_resources, + .num_resources = ARRAY_SIZE(rtc_resources), +}; + +void __init ns9xxx_add_device_ns9215_rtc(void) +{ + if (clk_register(&rtc_pm_clk.clk)) + return; + + rtc_clk.parent = &rtc_pm_clk.clk; + if (clk_register(&rtc_clk)) + return; + + if (request_irq(IRQ_NS9215_RTC, ns9xxx_plat_rtc_irq, IRQF_SHARED, + "plat-rtc-ns9xxx", ns9xxx_plat_rtc_irq)) + return; + + platform_device_register(&ns9xxx_device_ns9215_rtc); +} +#else +void __init ns9xxx_add_device_ns9215_rtc(void) {} +#endif diff --git a/arch/arm/mach-ns9xxx/ns9215_devices.h b/arch/arm/mach-ns9xxx/ns9215_devices.h new file mode 100644 index 000000000000..065c270b9350 --- /dev/null +++ b/arch/arm/mach-ns9xxx/ns9215_devices.h @@ -0,0 +1,14 @@ +/* + * arch/arm/mach-ns9xxx/ns9215_devices.h + * + * 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. + */ + +void __init ns9xxx_add_device_ns9215_leds(void); +void __init ns9xxx_add_device_ns9215_adc(void); +void __init ns9xxx_add_device_ns9215_rtc(void); diff --git a/arch/arm/mach-ns9xxx/ns921x_devices.c b/arch/arm/mach-ns9xxx/ns921x_devices.c new file mode 100644 index 000000000000..1814cb95782d --- /dev/null +++ b/arch/arm/mach-ns9xxx/ns921x_devices.c @@ -0,0 +1,798 @@ +/* + * arch/arm/mach-ns9xxx/ns921x_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/err.h> +#include <linux/gpio.h> +#include <linux/ns9xxx-eth.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/dma-mapping.h> + +#include <mach/regs-sys-ns921x.h> +#include <mach/ns921x-serial.h> +#include <mach/fim-ns921x.h> +#include <mach/gpio.h> + +#include "clock.h" +#include "ns921x_devices.h" +#include "processor-ns921x.h" + +/* 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_ns921x_wdt = { + .name = "ns9xxx-wdt", + .id = -1, + .resource = wdt_resources, + .num_resources = ARRAY_SIZE(wdt_resources), +}; + +void __init ns9xxx_add_device_ns921x_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_ns921x_wdt); +} +#else +void __init ns9xxx_add_device_ns921x_wdt(void) {} +#endif + +/* Ethernet */ +#if defined(CONFIG_NS9XXX_ETH) || defined(CONFIG_NS9XXX_ETH_MODULE) +int __init eth_register_gpios(int gpio[], int func[], int dir[], int num) +{ + int i; + + for (i = 0; i < num; i++) { + if (gpio_request(gpio[i], "ns9xxx-eth")) + goto err; + gpio_configure_ns921x(gpio[i], dir[i], 0, func[i], 0); + } + + return 0; +err: + for (; i >= 0; i--) + gpio_free(gpio[i]); + + return -EBUSY; +} + +static struct ns921x_sysclk eth_clk = { + .clk = { + .name = "ns9xxx-eth", + .id = -1, + .owner = THIS_MODULE, + .endisable = ns921x_endisable_sysclock, + }, + .mask = SYS_CLOCK_ETH, +}; + +static struct plat_ns9xxx_eth ns9xxx_device_ns921x_eth_data = { + .irqrx = IRQ_NS9XXX_ETHRX, + .irqtx = IRQ_NS9XXX_ETHTX, +#ifdef CONFIG_GPIO_ETH_ACTIVITY_LED + .activityled = 14, +#endif +}; + +static struct resource eth_resources[] = { + { + .start = 0xa0600000, + .end = 0xa06027ff, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device ns9xxx_device_ns921x_eth = { + .name = "ns9xxx-eth", + .id = -1, + .resource = eth_resources, + .num_resources = ARRAY_SIZE(eth_resources), + .dev = { + .platform_data = &ns9xxx_device_ns921x_eth_data, + }, +}; + +void __init ns9xxx_add_device_ns921x_eth(struct clk *phyclk, u32 phy_mask, + int gpio[], int func[], int dir[], int num) +{ + if (eth_register_gpios(gpio, func, dir, num)) + return; + + eth_clk.clk.parent = phyclk; + ns9xxx_device_ns921x_eth_data.phy_mask = phy_mask; + + if (clk_register(ð_clk.clk)) + return; + + platform_device_register(&ns9xxx_device_ns921x_eth); +} +#else +void __init ns9xxx_add_device_ns921x_eth(struct clk *phyclk, u32 phy_mask, + int gpio[], int func[], int dir[], int num) {} +#endif + +/* I2C controller */ +#if defined(CONFIG_I2C_NS9XXX) || defined(CONFIG_I2C_NS9XXX_MODULE) +static struct ns921x_sysclk i2c_clk = { + .clk = { + .name = "i2c-ns9xxx", + .id = -1, + .owner = THIS_MODULE, + .endisable = ns921x_endisable_sysclock, + }, + .mask = SYS_CLOCK_I2C, +}; + +static struct resource i2c_resources[] = { + { + .start = 0x90050000, + .end = 0x9005000f, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_NS921X_I2C, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device ns9xxx_device_ns921x_i2c = { + .name = "i2c-ns9xxx", + .id = -1, + .resource = i2c_resources, + .num_resources = ARRAY_SIZE(i2c_resources), +}; + +void __init ns9xxx_add_device_ns921x_i2c(struct plat_ns9xxx_i2c *i2c_data) +{ + i2c_clk.clk.parent = clk_get(NULL, "systemclock"); + if (IS_ERR(i2c_clk.clk.parent)) + return; + + if (clk_register(&i2c_clk.clk)) + return; + + ns9xxx_device_ns921x_i2c.dev.platform_data = i2c_data; + platform_device_register(&ns9xxx_device_ns921x_i2c); +} +#else +void __init ns9xxx_add_device_ns921x_i2c(struct plat_ns9xxx_i2c *i2c_data) {} +#endif + +/* UARTs */ +#if defined(CONFIG_SERIAL_NS921X) || defined(CONFIG_SERIAL_NS921X_MODULE) +static struct ns921x_sysclk uarta_clk = { + .clk = { + .name = "ns921x-serial", + .id = 0, + .owner = THIS_MODULE, + .rate = NS921X_REFCLOCK, + .endisable = ns921x_endisable_sysclock, + }, + .mask = SYS_CLOCK_UARTA, +}; + +static struct ns921x_sysclk uartb_clk = { + .clk = { + .name = "ns921x-serial", + .id = 1, + .owner = THIS_MODULE, + .rate = NS921X_REFCLOCK, + .endisable = ns921x_endisable_sysclock, + }, + .mask = SYS_CLOCK_UARTB, +}; + +static struct ns921x_sysclk uartc_clk = { + .clk = { + .name = "ns921x-serial", + .id = 2, + .owner = THIS_MODULE, + .rate = NS921X_REFCLOCK, + .endisable = ns921x_endisable_sysclock, + }, + .mask = SYS_CLOCK_UARTC, +}; + +static struct ns921x_sysclk uartd_clk = { + .clk = { + .name = "ns921x-serial", + .id = 3, + .owner = THIS_MODULE, + .rate = NS921X_REFCLOCK, + .endisable = ns921x_endisable_sysclock, + }, + .mask = SYS_CLOCK_UARTD, +}; + +static struct resource uarta_resources[] = { + { + .start = 0x90010000, + .end = 0x90017fff, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_NS921X_UARTA, + .flags = IORESOURCE_IRQ, + } +}; + +static struct resource uartb_resources[] = { + { + .start = 0x90018000, + .end = 0x9001ffff, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_NS921X_UARTB, + .flags = IORESOURCE_IRQ, + } +}; + +static struct resource uartc_resources[] = { + { + .start = 0x90020000, + .end = 0x90027fff, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_NS921X_UARTC, + .flags = IORESOURCE_IRQ, + } +}; + +static struct resource uartd_resources[] = { + { + .start = 0x90028000, + .end = 0x9002ffff, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_NS921X_UARTD, + .flags = IORESOURCE_IRQ, + } +}; + +static struct ns921x_uart_data uarta_data; +static struct ns921x_uart_data uartb_data; +static struct ns921x_uart_data uartc_data; +static struct ns921x_uart_data uartd_data; + +static struct platform_device ns9xxx_device_ns921x_uarta = { + .name = "ns921x-serial", + .id = 0, + .dev = { + .platform_data = &uarta_data, + }, + .resource = uarta_resources, + .num_resources = ARRAY_SIZE(uarta_resources), +}; + +static struct platform_device ns9xxx_device_ns921x_uartb = { + .name = "ns921x-serial", + .id = 1, + .dev = { + .platform_data = &uartb_data, + }, + .resource = uartb_resources, + .num_resources = ARRAY_SIZE(uartb_resources), +}; + +static struct platform_device ns9xxx_device_ns921x_uartc = { + .name = "ns921x-serial", + .id = 2, + .dev = { + .platform_data = &uartc_data, + }, + .resource = uartc_resources, + .num_resources = ARRAY_SIZE(uartc_resources), +}; + +static struct platform_device ns9xxx_device_ns921x_uartd = { + .name = "ns921x-serial", + .id = 3, + .dev = { + .platform_data = &uartd_data, + }, + .resource = uartd_resources, + .num_resources = ARRAY_SIZE(uartd_resources), +}; + +int __init uart_register_gpios(int gpio_start, + int gpio_nr, + int func, + struct ns921x_uart_data *data) +{ + int i; + int gpio[] = { 3, 7, 1, 5, 0, 2, 4, 6 }; + + for (i = 0; i < gpio_nr; i++) { + if (i!=2 || !data->rtsen) /* Skip request of CTS line */ + { + if (gpio_request(gpio_start + gpio[i], "ns921x-serial")) + goto err; +#ifdef CONFIG_NS921X_SERIAL_RTS_AS_GPIO + if (i==3) /* RTS needs to be used as gpio to allow using AFE */ + gpio_configure_ns921x(gpio_start + gpio[i], 0, 0, 3, 0); + else +#endif + gpio_configure_ns921x(gpio_start + gpio[i], 0, 0, func, 0); + } + data->gpios[i] = gpio_start + gpio[i]; + } + + return 0; +err: + for (; i >= 0; i--) + gpio_free(gpio_start + gpio[i]); + + return -EBUSY; +} + +void __init ns9xxx_add_device_ns921x_uarta(int gpio_start, + int gpio_nr, int func) +{ + uarta_data.nr_gpios = gpio_nr; +#if defined(CONFIG_CC9P9215JS_SERIAL_PORTA_RXTX485) || \ + defined(CONFIG_CME9210JS_SERIAL_PORTA_RXTX485) + uarta_data.rtsen = 1; +#else + uarta_data.rtsen = 0; +#endif + if (uart_register_gpios(gpio_start, gpio_nr, func, &uarta_data)) + return; + + if (clk_register(&uarta_clk.clk)) + return; + + platform_device_register(&ns9xxx_device_ns921x_uarta); +} + +void __init ns9xxx_add_device_ns921x_uartb(int gpio_start, + int gpio_nr, int func) +{ + uartb_data.nr_gpios = gpio_nr; +#ifdef CONFIG_CC9P9215JS_SERIAL_PORTB_RXTX485 + uartb_data.rtsen = 1; +#else + uartb_data.rtsen = 0; +#endif + + if (uart_register_gpios(gpio_start, gpio_nr, func, &uartb_data)) + return; + + if (clk_register(&uartb_clk.clk)) + return; + + platform_device_register(&ns9xxx_device_ns921x_uartb); +} + +void __init ns9xxx_add_device_ns921x_uartc(int gpio_start, + int gpio_nr, int func) +{ + uartc_data.nr_gpios = gpio_nr; +#ifdef CONFIG_CC9P9215JS_SERIAL_PORTC_RXTX485 + uartc_data.rtsen = 1; +#else + uartc_data.rtsen = 0; +#endif + + if (uart_register_gpios(gpio_start, gpio_nr, func, &uartc_data)) + return; + + if (clk_register(&uartc_clk.clk)) + return; + + platform_device_register(&ns9xxx_device_ns921x_uartc); +} + +void __init ns9xxx_add_device_ns921x_uartd(int gpio_start, + int gpio_nr, int func) +{ + uartd_data.nr_gpios = gpio_nr; +#ifdef CONFIG_CC9P9215JS_SERIAL_PORTD_RXTX485 + uartd_data.rtsen = 1; +#else + uartd_data.rtsen = 0; +#endif + + if (uart_register_gpios(gpio_start, gpio_nr, func, &uartd_data)) + return; + + if (clk_register(&uartd_clk.clk)) + return; + + platform_device_register(&ns9xxx_device_ns921x_uartd); +} +#else +void __init ns9xxx_add_device_ns921x_uarta(int gpio_start, + int gpio_nr, int func) {} +void __init ns9xxx_add_device_ns921x_uartb(int gpio_start, + int gpio_nr, int func) {} +void __init ns9xxx_add_device_ns921x_uartc(int gpio_start, + int gpio_nr, int func) {} +void __init ns9xxx_add_device_ns921x_uartd(int gpio_start, + int gpio_nr, int func) {} +#endif + +/* Flash */ +#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP) +static struct resource flash_resources[] = { + { + .start = 0x50000000, + .end = 0x5fffffff, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device ns9xxx_device_ns921x_flash = { + .name = "physmap-flash", + .id = 0, + .resource = flash_resources, + .num_resources = ARRAY_SIZE(flash_resources), +}; + +void __init ns9xxx_add_device_ns921x_flash( + struct physmap_flash_data *flash_data) +{ + + ns9xxx_device_ns921x_flash.dev.platform_data = flash_data; + platform_device_register(&ns9xxx_device_ns921x_flash); +} +#else +void __init ns9xxx_add_device_ns921x_flash( + struct physmap_flash_data *flash_data) {} +#endif + +/* SPI port */ +#if defined(CONFIG_SPI_NS921X) || defined(CONFIG_SPI_NS921X_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_ns921x")) + goto err; + gpio_configure_ns921x(data->gpios[i], + 0, + 0, + data->gpio_funcs[i], + 0 ); + } + + return 0; +err: + for (; i >= 0; i--) + gpio_free(data->gpios[i]); + + return -EBUSY; +} + +static struct ns921x_sysclk spi_clk = { + .clk = { + .name = "spi_ns921x", + .id = 1, + .owner = THIS_MODULE, + .endisable = ns921x_endisable_sysclock, + }, + .mask = SYS_CLOCK_SPI, +}; + +static struct resource spi_resources[] = { + { + .start = 0x90030000, + .end = 0x90037fff, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_NS921X_SPI, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 spi_dmamask = DMA_BIT_MASK(32); + +static struct platform_device ns9xxx_device_ns921x_spi = { + .name = "spi_ns921x", + .id = 1, + .resource = spi_resources, + .num_resources = ARRAY_SIZE(spi_resources), + .dev = { + .dma_mask = &spi_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +void __init ns9xxx_add_device_ns921x_spi(struct spi_ns9xxx_data *data) +{ + if (spi_register_gpios(data)) + return; + + spi_clk.clk.parent = clk_get(NULL, "systemclock"); + if (IS_ERR(spi_clk.clk.parent)) + return; + + if (clk_register(&spi_clk.clk)) + return; + + ns9xxx_device_ns921x_spi.dev.platform_data = data; + platform_device_register(&ns9xxx_device_ns921x_spi); +} +#else +void __init ns9xxx_add_device_ns921x_spi(struct spi_ns9xxx_data *data) {} +#endif + +/* AES HW Encryption module */ +#if defined(CONFIG_CRYPTO_DEV_NS921X_AES) || \ + defined(CONFIG_CRYPTO_DEV_NS921X_AES_MODULE) +static struct ns921x_sysclk aes_clk = { + .clk = { + .name = "ns921x-aes", + .id = -1, + .owner = THIS_MODULE, + .endisable = ns921x_endisable_sysclock, + }, + .mask = SYS_CLOCK_AES, +}; + +static struct resource aes_resources[] = { + { + .start = 0xa0800000, + .end = 0xa080000f, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_NS921X_EXTDMA, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 aes_dmamask = DMA_BIT_MASK(32); + +static struct platform_device ns9xxx_device_ns921x_aes = { + .name = "ns921x-aes", + .id = 1, + .resource = aes_resources, + .num_resources = ARRAY_SIZE(aes_resources), + .dev = { + .dma_mask = &aes_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +void __init ns9xxx_add_device_ns921x_aes(void) +{ + aes_clk.clk.parent = clk_get(NULL, "dmaclock"); + if (IS_ERR(aes_clk.clk.parent)) + return; + + if (clk_register(&aes_clk.clk)) + return; + + platform_device_register(&ns9xxx_device_ns921x_aes); +} +#else +void __init ns9xxx_add_device_ns921x_aes(void); +#endif + + +#if defined(CONFIG_PM) +static irqreturn_t ns921x_ack_extirq(int irq, void *dev_id) +{ + u32 eixctl; + + BUG_ON((unsigned)(irq - IRQ_NS9XXX_EXT0) > 4); + + eixctl = __raw_readl(SYS_EIxCTRL(irq - IRQ_NS9XXX_EXT0)); + + /* ack ext irq */ + REGSETIM(eixctl, SYS_EIxCTRL, CLEAR, 1); + __raw_writel(eixctl, SYS_EIxCTRL(irq - IRQ_NS9XXX_EXT0)); + REGSETIM(eixctl, SYS_EIxCTRL, CLEAR, 0); + __raw_writel(eixctl, SYS_EIxCTRL(irq - IRQ_NS9XXX_EXT0)); + + return IRQ_HANDLED; +} + +int __init ns921x_extgpio_pm_wakeup_init(unsigned int gpio) +{ + int ret; + const struct gpio_to_irq_map *map; + + map = gpio_get_map_ns921x(gpio); + if (!map) { + pr_debug("%s: selected gpio %d not irq capable\n", __func__, gpio); + return -EINVAL; + } + + ret = gpio_request(gpio, "cpuwake"); + if (ret) { + pr_debug("%s: err_gpio_request -> %d\n", __func__, ret); + goto err_gpio_request; + } + + gpio_configure_ns921x(gpio, 0, 0, map->func, 0); + + ret = request_irq(map->irq, ns921x_ack_extirq, IRQF_TRIGGER_FALLING, + "extwakeirq", NULL); + if (ret) { + pr_debug("%s: err_request_irq_extwakeirq %d -> %d\n", __func__, map->irq, ret); + goto err_irq_request; + } + + ret = enable_irq_wake(map->irq); + if (ret) { + pr_debug("%s: err_enable_irq_extwakeirq %d -> %d\n", __func__, map->irq, ret); + goto err_enable_wake; + } + return 0; + +err_enable_wake: + free_irq(map->irq, NULL); +err_irq_request: + gpio_free(gpio); +err_gpio_request: + return ret; +} +#else /* CONFIG_PM */ +int __init ns921x_extgpio_pm_wakeup_init(unsigned int gpio) +{ + return 0; +} +#endif /* CONFIG_PM */ + +#if defined(CONFIG_FIM_ZERO_SDIO) +void __init ns9xxx_add_device_ns921x_fim_sdio0(void) +{ + extern struct platform_device ns921x_fim_sdio0; + platform_device_register(&ns921x_fim_sdio0); +} +#else +void __init ns9xxx_add_device_ns921x_fim_sdio0(void) {} +#endif + +#if defined(CONFIG_FIM_ONE_SDIO) +void __init ns9xxx_add_device_ns921x_fim_sdio1(void) +{ + extern struct platform_device ns921x_fim_sdio1; + platform_device_register(&ns921x_fim_sdio1); +} +#else +void __init ns9xxx_add_device_ns921x_fim_sdio1(void) {} +#endif + + +#if defined(CONFIG_FIM_ZERO_SERIAL) +void __init ns9xxx_add_device_ns921x_fim_serial0(void) +{ + extern struct platform_device ns921x_fim_serial0; + platform_device_register(&ns921x_fim_serial0); +} +#else +void __init ns9xxx_add_device_ns921x_fim_serial0(void) {} +#endif /* CONFIG_FIM_SERIAL */ + +#if defined(CONFIG_FIM_ONE_SERIAL) +void __init ns9xxx_add_device_ns921x_fim_serial1(void) +{ + extern struct platform_device ns921x_fim_serial1; + platform_device_register(&ns921x_fim_serial1); +} +#else +void __init ns9xxx_add_device_ns921x_fim_serial1(void) {} +#endif /* CONFIG_FIM_SERIAL */ + +#if defined(CONFIG_FIM_ZERO_CAN) +void __init ns9xxx_add_device_ns921x_fim_can0(void) +{ + extern struct platform_device ns921x_fim_can0; + platform_device_register(&ns921x_fim_can0); +} +#else +void __init ns9xxx_add_device_ns921x_fim_can0(void) {} +#endif + +#if defined(CONFIG_FIM_ONE_CAN) +void __init ns9xxx_add_device_ns921x_fim_can1(void) +{ + extern struct platform_device ns921x_fim_can1; + platform_device_register(&ns921x_fim_can1); +} +#else +void __init ns9xxx_add_device_ns921x_fim_can1(void) {} +#endif + +#if defined(CONFIG_FIM_ZERO_W1) +static void __init ns9xxx_add_device_ns921x_fim0_w1(void) +{ + extern struct platform_device ns921x_fim0_w1; + platform_device_register(&ns921x_fim0_w1); +} +#else +static inline void __init ns9xxx_add_device_ns921x_fim0_w1(void) { } +#endif + +#if defined(CONFIG_FIM_ONE_W1) +static void __init ns9xxx_add_device_ns921x_fim1_w1(void) +{ + extern struct platform_device ns921x_fim1_w1; + platform_device_register(&ns921x_fim1_w1); +} +#else +static inline void __init ns9xxx_add_device_ns921x_fim1_w1(void) { } +#endif + +#if defined(CONFIG_FIM_ZERO_USB) +void __init ns9xxx_add_device_ns921x_fim_usb0(void) +{ + extern struct platform_device ns921x_fim_usb0; + platform_device_register(&ns921x_fim_usb0); +} +#else +static inline void __init ns9xxx_add_device_ns921x_fim_usb0(void) {} +#endif + +#if defined(CONFIG_FIM_ONE_USB) +void __init ns9xxx_add_device_ns921x_fim_usb1(void) +{ + extern struct platform_device ns921x_fim_usb1; + platform_device_register(&ns921x_fim_usb1); +} +#else +static inline void __init ns9xxx_add_device_ns921x_fim_usb1(void) {} +#endif + +#if defined(CONFIG_FIM_CORE) || defined(CONFIG_FIM_MODULES) +void __init ns9xxx_add_device_ns921x_fims(void) +{ + /* + * By the CME9210s with the CAN-support the GPIOs 2 and 23 are inter-connected. + * This is just problematic when these modules should use the FIM-serial + * interface, then the GPIO23 is not configured as input GPIO after the resets. + * IMPORTANT: The below code will disappear in one of the next U-Boot releases + * with the FIMs-support. + * (Luis Galdos) + */ +#if defined(CONFIG_FIM_CORE) && \ + (defined(CONFIG_MACH_CME9210) || defined(CONFIG_MACH_CME9210JS)) + gpio_direction_input_ns921x_unlocked(23); +#endif + + /* FIM 0 */ + ns9xxx_add_device_ns921x_fim_serial0(); + ns9xxx_add_device_ns921x_fim_sdio0(); + ns9xxx_add_device_ns921x_fim_can0(); + ns9xxx_add_device_ns921x_fim0_w1(); + ns9xxx_add_device_ns921x_fim_usb0(); + + /* FIM 1 */ + ns9xxx_add_device_ns921x_fim_serial1(); + ns9xxx_add_device_ns921x_fim_sdio1(); + ns9xxx_add_device_ns921x_fim_can1(); + ns9xxx_add_device_ns921x_fim1_w1(); + ns9xxx_add_device_ns921x_fim_usb1(); +} +#else +void __init ns9xxx_add_device_ns921x_fims(void) {} +#endif /* CONFIG_FIM_CORE */ + diff --git a/arch/arm/mach-ns9xxx/ns921x_devices.h b/arch/arm/mach-ns9xxx/ns921x_devices.h new file mode 100644 index 000000000000..d1e7e7153cdf --- /dev/null +++ b/arch/arm/mach-ns9xxx/ns921x_devices.h @@ -0,0 +1,37 @@ +/* + * arch/arm/mach-ns9xxx/ns921x_devices.h + * + * 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/i2c-ns9xxx.h> +#include <linux/init.h> +#include <linux/mtd/physmap.h> +#include <mach/spi.h> + +#include "clock.h" + +void __init ns9xxx_add_device_ns921x_wdt(void); +void __init ns9xxx_add_device_ns921x_eth(struct clk *phyclk, u32 phy_mask, + int gpio[], int func[], int dir[], int num); +void __init ns9xxx_add_device_ns921x_i2c(struct plat_ns9xxx_i2c *); +void __init ns9xxx_add_device_ns921x_uarta(int gpio_start, + int gpio_nr, int func); +void __init ns9xxx_add_device_ns921x_uartb(int gpio_start, + int gpio_nr, int func); +void __init ns9xxx_add_device_ns921x_uartc(int gpio_start, + int gpio_nr, int func); +void __init ns9xxx_add_device_ns921x_uartd(int gpio_start, + int gpio_nr, int func); +void __init ns9xxx_add_device_ns921x_flash( + struct physmap_flash_data *flash_data); +void __init ns9xxx_add_device_ns921x_spi(struct spi_ns9xxx_data *data); +int __init ns921x_extgpio_pm_wakeup_init(unsigned int gpio); +void __init ns9xxx_add_device_ns921x_fims(void); +void __init ns9xxx_add_device_ns921x_aes(void); 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 diff --git a/arch/arm/mach-ns9xxx/ns9360_devices.h b/arch/arm/mach-ns9xxx/ns9360_devices.h new file mode 100644 index 000000000000..1994532aa3a1 --- /dev/null +++ b/arch/arm/mach-ns9xxx/ns9360_devices.h @@ -0,0 +1,32 @@ +/* + * arch/arm/mach-ns9xxx/ns9360_devices.h + * + * 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/i2c-ns9xxx.h> +#include <linux/init.h> +#include <linux/mtd/ccx9x_nand.h> +#include <mach/spi.h> + +void __init ns9xxx_add_device_ns9360_usbh(void); +void __init ns9xxx_add_device_ns9360_wdt(void); +void __init ns9xxx_add_device_ns9360_rtc(void); +void __init ns9xxx_add_device_ns9360_eth(int gpio[], int gpio_nr, int func, u32 phy_mask); +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); +void __init ns9xxx_add_device_ns9360_nand(struct ccx9x_nand_info *); +void __init ns9xxx_add_device_ns9360_i2c(struct plat_ns9xxx_i2c *); +void __init ns9xxx_add_device_ns9360_fb(int gpio[], int gpio_nr, + int func[], int power); +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); diff --git a/arch/arm/mach-ns9xxx/pm-ns921x.c b/arch/arm/mach-ns9xxx/pm-ns921x.c new file mode 100644 index 000000000000..5ecd5bb5b1bf --- /dev/null +++ b/arch/arm/mach-ns9xxx/pm-ns921x.c @@ -0,0 +1,173 @@ +/* + * arch/arm/mach-ns9xxx/pm-ns921x.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/init.h> +#include <linux/interrupt.h> +#include <linux/suspend.h> +#include <linux/gpio.h> + +#include <asm/io.h> +#include <asm/leds.h> + +#include <mach/processor.h> +#include <mach/regs-sys-ns921x.h> +#include <mach/irqs.h> + +#include "processor-ns921x.h" + +#define NS921X_PM_ENET (1 << 0) +#define NS921X_PM_UART (0xf << 1) +#define NS921X_PM_SPI (1 << 5) +#define NS921X_PM_I2C (1 << 11) +#define NS921X_PM_RTC (1 << 12) +#define NS921X_PM_I2C (1 << 11) +#define NS921X_PM_EXT0 (1 << 16) +#define NS921X_PM_EXT1 (1 << 17) +#define NS921X_PM_EXT2 (1 << 18) +#define NS921X_PM_EXT3 (1 << 19) +#define NS921X_PM_ALL_WK 0xf183f + +#if defined(DEBUG) +#define REGMAP(reg) { .name = #reg, .addr = reg, } +static const struct { + const char *name; + void __iomem *addr; +} regmap[] = { + REGMAP(SYS_ISA), + REGMAP(SYS_ISR), + REGMAP(SYS_CLOCK), + REGMAP(SYS_POWER), +}; + +static void dump_regs(void) +{ + int i; + for (i = 0; i < ARRAY_SIZE(regmap); ++i) + pr_debug("%s = 0x%08x\n", regmap[i].name, + __raw_readl(regmap[i].addr)); +} +#else +#define dump_regs() ((void)0) +#endif + +static irqreturn_t ns921x_cpuwake_irq(int irq, void *dev_id) +{ + u32 power = __raw_readl(SYS_POWER); + + /* ack wake irq */ + __raw_writel(power | SYS_POWER_INTCLR, SYS_POWER); + __raw_writel(power, SYS_POWER); + + return IRQ_HANDLED; +} + +static int ns921x_pm_prepare(void) +{ + int ret; + + ret = request_irq(IRQ_NS921X_CPUWAKE, ns921x_cpuwake_irq, 0, "cpuwake", + NULL); + if (ret) { + pr_debug("%s: err_%s -> %d\n", + __func__, "request_irq_cpuwake", ret); + } + + return ret; +} + +extern int ns9xxx_is_enabled_irq(unsigned int irq); + +static int ns921x_pm_enter(suspend_state_t state) +{ + u32 power = __raw_readl(SYS_POWER) | SYS_POWER_SLFRFSH; + + /* ack any possible wake up irq before going to sleep... */ + __raw_writel(power | SYS_POWER_INTCLR, SYS_POWER); + __raw_writel(power, SYS_POWER); + + power &= NS921X_PM_ALL_WK; + if (!power) + goto pm_enter_err; + + /* Verify that, if only one source is enabled that at least + * that irq is enabled */ + if (!(power & ~NS921X_PM_ENET)) { + if (!ns9xxx_is_enabled_irq(IRQ_NS9XXX_ETHRX)) + goto pm_enter_err; + } + + if (!(power & ~NS921X_PM_UART)) { + if (!ns9xxx_is_enabled_irq(IRQ_NS921X_UARTA) | + !ns9xxx_is_enabled_irq(IRQ_NS921X_UARTB) | + !ns9xxx_is_enabled_irq(IRQ_NS921X_UARTC) | + !ns9xxx_is_enabled_irq(IRQ_NS921X_UARTD)) + goto pm_enter_err; + } + + if (!(power & ~NS921X_PM_RTC)) { + if (!ns9xxx_is_enabled_irq(IRQ_NS9215_RTC)) + goto pm_enter_err; + } + + if (!(power & ~NS921X_PM_EXT0)) { + if (!ns9xxx_is_enabled_irq(IRQ_NS9XXX_EXT0)) + goto pm_enter_err; + } + + if (!(power & ~NS921X_PM_EXT1)) { + if (!ns9xxx_is_enabled_irq(IRQ_NS9XXX_EXT1)) + goto pm_enter_err; + } + + if (!(power & ~NS921X_PM_EXT2)) { + if (!ns9xxx_is_enabled_irq(IRQ_NS9XXX_EXT2)) + goto pm_enter_err; + } + + if (!(power & ~NS921X_PM_EXT3)) { + if (!ns9xxx_is_enabled_irq(IRQ_NS9XXX_EXT3)) + goto pm_enter_err; + } + + leds_event(led_idle_start); + asm volatile("mcr p15, 0, %0, c7, c0, 4" : : "r" (0)); + leds_event(led_idle_end); + + return 0; + +pm_enter_err: + pr_warning("No wakeup source or interface disabled, not going to sleep (0x%08x)\n", + __raw_readl(SYS_POWER)); + return -EDEADLK; + +} + +static void ns921x_pm_finish(void) +{ + free_irq(IRQ_NS921X_CPUWAKE, NULL); +} + +static struct platform_suspend_ops ns921x_pm_ops = { + .valid = suspend_valid_only_mem, + .prepare = ns921x_pm_prepare, + .enter = ns921x_pm_enter, + .finish = ns921x_pm_finish, +}; + +static int __init ns921x_pm_init(void) +{ + if (!processor_is_ns921x()) + return -ENODEV; + + suspend_set_ops(&ns921x_pm_ops); + return 0; +} +arch_initcall(ns921x_pm_init); diff --git a/arch/arm/mach-ns9xxx/processor-ns921x.c b/arch/arm/mach-ns9xxx/processor-ns921x.c new file mode 100644 index 000000000000..cc0a49ccbc87 --- /dev/null +++ b/arch/arm/mach-ns9xxx/processor-ns921x.c @@ -0,0 +1,379 @@ +/* + * arch/arm/mach-ns9xxx/processor-ns921x.c + * + * Copyright (C) 2007,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/cpufreq.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/slab.h> + +#include <asm/page.h> +#include <asm/mach/map.h> + +#include <mach/regs-mem.h> +#include <mach/regs-sys-ns921x.h> + +#include "clock.h" + +#include "processor-ns921x.h" +#include "gpiolib-ns921x.h" + +void ns921x_reset(char mode) +{ + unsigned long pll = __raw_readl(SYS_PLL); + __raw_writel(pll, SYS_PLL); +} + +#define DIVMASK(mask) ((mask) & (-(mask))) +#define MASKVALUE(value, mask) (((value) & (mask)) / DIVMASK(mask)) + +unsigned long ns921x_systemclock(void) +{ + unsigned long pll = __raw_readl(SYS_PLL); + unsigned pll_nr = MASKVALUE(pll, SYS_PLL_NR); + unsigned pll_nf = MASKVALUE(pll, SYS_PLL_NF); + unsigned pll_od = MASKVALUE(pll, SYS_PLL_OD); + + return NS921X_REFCLOCK / (pll_nr + 1) * (pll_nf + 1) / (pll_od + 1); +} +static unsigned long ns921x_get_systemclock_rate(struct clk *clk) +{ + return ns921x_systemclock(); +} + +static inline unsigned long ahbclock(u32 clock) +{ + return ns921x_systemclock() >> (MASKVALUE(clock, SYS_CLOCK_CSC) + 2); +} + +unsigned long ns921x_ahbclock(void) +{ + unsigned long clock = __raw_readl(SYS_CLOCK); + return ahbclock(clock); +} + +static unsigned long ns921x_get_ahbclock_rate(struct clk *clk) +{ + return ns921x_ahbclock(); +} + +static inline unsigned long cpuclock(u32 clock) +{ + return ahbclock(clock) << MASKVALUE(clock, SYS_CLOCK_CSSEL); +} + +static unsigned long ns921x_cpuclock(void) +{ + unsigned long clock = __raw_readl(SYS_CLOCK); + return cpuclock(clock); +} + +static unsigned long ns921x_get_cpuclock_rate(struct clk *clk) +{ + return ns921x_cpuclock(); +} + +#if defined(CONFIG_CPU_FREQ) +static inline int ns921x_freq2clock(unsigned int freq /* [kHz] */, + u32 cssel) +{ + /* valid range for CSC = [0...4] */ + int i, found = 0; + + BUG_ON(cssel && (cssel != SYS_CLOCK_CSSEL)); + pr_debug("%s: freq = %u\n", __func__, freq); + + for (i = 4; i >= 0; --i) { + u32 clock = i << 29 | cssel; + found = cpuclock(clock) >= 1000UL * freq; + if (found) + break; + } + if (!found) { + pr_debug("%s(%u, 0x%x) failed\n", __func__, freq, cssel); + BUG(); + } + + return i << 29 | cssel; +} + +/* refresh_timer hold the value of the MEM_DMRT register for full speed + * operation (SYS_CLOCK_SYS = 0b000) + */ +static u32 refresh_timer; + +static int ns921x_cpufreq_verify(struct cpufreq_policy *policy) +{ + unsigned int freq; + u32 cssel = 0; + + pr_debug("%s\n", __func__); + /* This is an UP machine */ + if (policy->cpu) + return -EINVAL; + + if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) + cssel = SYS_CLOCK_CSSEL; + + cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, + policy->cpuinfo.max_freq); + + /* XXX: make sure there is at least one frequency within the policy */ + freq = cpuclock(ns921x_freq2clock(policy->min, cssel)) / 1000; + if (freq > policy->max) + policy->max = freq; + + cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, + policy->cpuinfo.max_freq); + + pr_debug("/%s\n", __func__); + return 0; +} + +static inline void update_refresh_timer(u32 clock) +{ + u32 rt = (refresh_timer >> (clock >> 29)); + + if (unlikely(!rt)) { + pr_warning("Cannot adapt the Dynamic Memory Refresh Timer: " + "clock=0x%08x, rftimer=0x%08x", + clock, refresh_timer); + rt = 1; + } else { + if (unlikely(rt > 0x7ff)) + rt = 0x7ff; + pr_debug("%s: MEM_DMRT <- 0x%08x\n", __func__, rt); + } + __raw_writel(rt, MEM_DMRT); +} + +static int ns921x_cpufreq_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + struct cpufreq_freqs freqs; + unsigned long flags; + u32 cssel = 0; + u32 clock; + + pr_debug("%s\n", __func__); + if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) + cssel = SYS_CLOCK_CSSEL; + + clock = ns921x_freq2clock(target_freq, cssel); + + pr_debug("%s: targetfreq = %u, relation = %u, new clock = %lx\n", + __func__, target_freq, relation, (unsigned long)clock); + + if (relation == CPUFREQ_RELATION_H && + cpuclock(clock) / 1000 != target_freq) { + clock += 1 << 29; + BUG_ON((clock >> 29) > 4); + } + + freqs.cpu = policy->cpu; + freqs.old = policy->cur; + + freqs.new = cpuclock(clock) / 1000; + + pr_debug("%s: new = %u kHz, CLOCK=%lx\n", __func__, freqs.new, + (unsigned long)clock); + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + local_irq_save(flags); + + if (freqs.old > freqs.new) + update_refresh_timer(clock); + + clock |= __raw_readl(SYS_CLOCK) & ~(SYS_CLOCK_CSC | SYS_CLOCK_CSSEL); + + pr_debug("%s: SYS_CLOCK <- %x (%lu)\n", __func__, clock, cpuclock(clock)); + __raw_writel(clock, SYS_CLOCK); + + if (freqs.old < freqs.new) + update_refresh_timer(clock); + + local_irq_restore(flags); + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + pr_debug("/%s\n", __func__); + + return 0; +} + +static unsigned int ns921x_cpufreq_get(unsigned int cpu) +{ + BUG_ON(cpu); + + return ns921x_cpuclock() / 1000; +} + +static int ns921x_cpufreq_init(struct cpufreq_policy *policy) +{ + u32 clock = __raw_readl(SYS_CLOCK); + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; + policy->policy = CPUFREQ_POLICY_PERFORMANCE; + policy->cpuinfo.min_freq = cpuclock(4 << 29 | SYS_CLOCK_CSSEL) / 1000; + policy->cpuinfo.max_freq = cpuclock(SYS_CLOCK_CSSEL) / 1000; + policy->cpuinfo.transition_latency = 1; /* XXX ??? */ + policy->cur = ns921x_cpufreq_get(0); + policy->min = policy->cpuinfo.min_freq; + policy->max = policy->cpuinfo.max_freq; + + refresh_timer = __raw_readl(MEM_DMRT) << (clock >> 29); + + pr_info("ns921x CPU frequency change support initialized\n"); + pr_debug("%s: cur = %u, min = %d, max = %d\n", __func__, policy->cur, + policy->cpuinfo.min_freq, policy->cpuinfo.max_freq); + + return 0; +} + +static struct cpufreq_driver ns921x_cpufreq_driver = { + .flags = CPUFREQ_STICKY, + .verify = ns921x_cpufreq_verify, + .target = ns921x_cpufreq_target, + .get = ns921x_cpufreq_get, + .init = ns921x_cpufreq_init, + .name = "ns921x", +}; +#endif + +static struct map_desc ns921x_io_desc[] __initdata = { + { /* Memory Controller */ + .virtual = io_p2v(0xa0700000), + .pfn = __phys_to_pfn(0xa0700000), + .length = 0x27c, + .type = MT_DEVICE, + }, + { /* External DMA Module */ + .virtual = io_p2v(0xa0800000), + .pfn = __phys_to_pfn(0xa0800000), + .length = 0x20, + .type = MT_DEVICE, + }, + { /* System Control Module */ + .virtual = io_p2v(0xa0900000), + .pfn = __phys_to_pfn(0xa0900000), + .length = 0x1000, + .type = MT_DEVICE, + }, + { /* I/O Control Module */ + .virtual = io_p2v(0xa0902000), + .pfn = __phys_to_pfn(0xa0902000), + .length = 0x90, + .type = MT_DEVICE, + }, +}; + +void __init ns921x_map_io(void) +{ + iotable_init(ns921x_io_desc, ARRAY_SIZE(ns921x_io_desc)); +} + +static inline void ns921x_setclock(u32 mask, u32 value) +{ + u32 oldclock = __raw_readl(SYS_CLOCK), clock; + + BUG_ON(value & ~mask); + + clock = (oldclock & ~mask) | value; + + __raw_writel(clock, SYS_CLOCK); +} + +static inline void ns921x_setreset(u32 mask, u32 value) +{ + u32 oldreset = __raw_readl(SYS_RESET), reset; + + BUG_ON(value & ~mask); + + reset = (oldreset & ~mask) | value; + + if (reset != oldreset) + __raw_writel(reset, SYS_RESET); +} + +int ns921x_endisable_sysclock(struct clk *clk, int enable) +{ + struct ns921x_sysclk *sysclk = + container_of(clk, struct ns921x_sysclk, clk); + unsigned long flags; + + local_irq_save(flags); + + if (enable) { + ns921x_setreset(sysclk->mask, sysclk->mask); + ns921x_setclock(sysclk->mask, sysclk->mask); + } else { + ns921x_setclock(sysclk->mask, 0); +#if defined(CONFIG_RESET_DISABLED_MODULES) + ns921x_setreset(sysclk->mask, 0); +#endif + } + + local_irq_restore(flags); + + return 0; +} + +void ns921x_init_machine(void) +{ + /* register system, ahb and cpu clocks */ + struct clk *clk = kzalloc(3 * sizeof(*clk), GFP_KERNEL); + struct ns921x_sysclk *dmaclk; + int ret, i; + + if (!clk) { + pr_warning("%s: could not register system clocks\n", __func__); + return; + } + + clk[0].name = "systemclock"; + clk[0].get_rate = ns921x_get_systemclock_rate; + + clk[1].name = "ahbclock"; + clk[1].get_rate = ns921x_get_ahbclock_rate; + + clk[2].name = "cpuclock"; + clk[2].get_rate = ns921x_get_cpuclock_rate; + + for (i = 0; i < 3; ++i) { + clk[i].id = -1; + ret = clk_register(&clk[i]); + if (ret) + pr_warning("%s: could not register %s\n", + __func__, clk[i].name); + } + + dmaclk = kzalloc(sizeof(*dmaclk), GFP_KERNEL); + if (!dmaclk) { + pr_warning("%s: could not register dma clock\n", __func__); + return; + } + + dmaclk->clk.name = "dmaclock"; + dmaclk->clk.id = -1; + dmaclk->clk.endisable = ns921x_endisable_sysclock; + dmaclk->clk.owner = THIS_MODULE; + dmaclk->mask = 1 << 14; + + ret = clk_register(&dmaclk->clk); + if (ret) + pr_warning("%s: could not register dma clock\n", __func__); + +#if defined(CONFIG_CPU_FREQ) + cpufreq_register_driver(&ns921x_cpufreq_driver); +#endif + + /* add system GPIOs */ + ns921x_gpio_init(); +} diff --git a/arch/arm/mach-ns9xxx/processor-ns921x.h b/arch/arm/mach-ns9xxx/processor-ns921x.h new file mode 100644 index 000000000000..a5c91a63c911 --- /dev/null +++ b/arch/arm/mach-ns9xxx/processor-ns921x.h @@ -0,0 +1,44 @@ +/* + * arch/arm/mach-ns9xxx/processor-ns921x.h + * + * Copyright (C) 2007,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. + */ +#ifndef __NS9XXX_PROCESSOR_NS921X_H +#define __NS9XXX_PROCESSOR_NS921X_H +#include <linux/init.h> + +#include "clock.h" + +#define NS921X_REFCLOCK 29491200 + +void ns921x_reset(char mode); + +unsigned long ns921x_systemclock(void) __attribute__((const)); + +unsigned long ns921x_ahbclock(void) __attribute__((const)); + +void __init ns921x_map_io(void); + +extern struct sys_timer ns921x_timer; + +struct ns921x_sysclk { + struct clk clk; + u32 mask; +}; +/* + * only use ns921x_endisable_sysclock as callback for struct ns921x_sysclk's + * because there is no additional locking to serialize access to SYS_CLOCK. + */ +int ns921x_endisable_sysclock(struct clk *clk, int enable); + +void __init ns921x_init_machine(void); + +/* irq-ns921x.c */ +int ns921x_set_wake_irq(unsigned int irq, unsigned int on); + +#endif /* ifndef __NS9XXX_PROCESSOR_NS921X_H */ diff --git a/arch/arm/mach-ns9xxx/processor-ns9360.c b/arch/arm/mach-ns9xxx/processor-ns9360.c index abee8338735d..ca9475ed1b62 100644 --- a/arch/arm/mach-ns9xxx/processor-ns9360.c +++ b/arch/arm/mach-ns9xxx/processor-ns9360.c @@ -1,7 +1,7 @@ /* * arch/arm/mach-ns9xxx/processor-ns9360.c * - * Copyright (C) 2007 by Digi International Inc. + * Copyright (C) 2007,2008 by Digi International Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify it @@ -14,9 +14,14 @@ #include <asm/page.h> #include <asm/mach/map.h> -#include <mach/processor-ns9360.h> + #include <mach/regs-sys-ns9360.h> +#include "clock.h" + +#include "processor-ns9360.h" +#include "gpiolib-ns9360.h" + void ns9360_reset(char mode) { u32 reg; @@ -34,6 +39,36 @@ unsigned long ns9360_systemclock(void) >> REGGETIM(pll, SYS_PLL, FS); } +unsigned long ns9360_cpuclock(void) +{ + return ns9360_systemclock() / 2; +} + +unsigned long ns9360_ahbclock(void) +{ + return ns9360_systemclock() / 4; +} + +static unsigned long ns9360_get_systemclock_rate(struct clk *clk) +{ + return ns9360_systemclock(); +} + +static unsigned long ns9360_get_bbusclock_rate(struct clk *clk) +{ + return ns9360_systemclock() / 8; +} + +static unsigned long ns9360_get_cpuclock_rate(struct clk *clk) +{ + return ns9360_cpuclock(); +} + +static unsigned long ns9360_get_ahbclock_rate(struct clk *clk) +{ + return ns9360_ahbclock(); +} + static struct map_desc ns9360_io_desc[] __initdata = { { /* BBus */ .virtual = io_p2v(0x90000000), @@ -52,3 +87,39 @@ void __init ns9360_map_io(void) { iotable_init(ns9360_io_desc, ARRAY_SIZE(ns9360_io_desc)); } + +void ns9360_init_machine(void) +{ + /* register system, bbus and cpu clocks */ + struct clk *clk = kzalloc(4 * sizeof(*clk), GFP_KERNEL); + int ret, i; + + if (!clk) { + pr_warning("%s: could not register system clocks\n", __func__); + return; + } + + clk[0].name = "systemclock"; + clk[0].get_rate = ns9360_get_systemclock_rate; + + clk[1].name = "bbusclock"; + clk[1].get_rate = ns9360_get_bbusclock_rate; + + clk[2].name = "cpuclock"; + clk[2].get_rate = ns9360_get_cpuclock_rate; + + clk[3].name = "ahbclock"; + clk[3].get_rate = ns9360_get_ahbclock_rate; + + for (i = 0; i < 4; ++i) { + clk[i].id = -1; + ret = clk_register(&clk[i]); + if (ret) + pr_warning("%s: could not register %s\n", + __func__, clk[i].name); + + } + + /* add system GPIOs */ + ns9360_gpio_init(); +} diff --git a/arch/arm/mach-ns9xxx/processor-ns9360.h b/arch/arm/mach-ns9xxx/processor-ns9360.h new file mode 100644 index 000000000000..7fbb79e0cbb1 --- /dev/null +++ b/arch/arm/mach-ns9xxx/processor-ns9360.h @@ -0,0 +1,30 @@ +/* + * arch/arm/mach-ns9xxx/processor-ns9360.h + * + * Copyright (C) 2007,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. + */ +#ifndef __NS9XXX_PROCESSOR_NS9360_H +#define __NS9XXX_PROCESSOR_NS9360_H + +#include <linux/init.h> + +#include "clock.h" + +void ns9360_reset(char mode); + +unsigned long ns9360_systemclock(void) __attribute__((const)); + +unsigned long ns9360_cpuclock(void) __attribute__((const)); + +void __init ns9360_map_io(void); + +extern struct sys_timer ns9360_timer; + +void __init ns9360_init_machine(void); + +#endif /* ifndef __NS9XXX_PROCESSOR_NS9360_H */ diff --git a/arch/arm/mach-ns9xxx/time-ns921x.c b/arch/arm/mach-ns9xxx/time-ns921x.c new file mode 100644 index 000000000000..5e5d54608e00 --- /dev/null +++ b/arch/arm/mach-ns9xxx/time-ns921x.c @@ -0,0 +1,195 @@ +/* + * arch/arm/mach-ns9xxx/time-ns921x.c + * + * Copyright (C) 2007 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/jiffies.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/stringify.h> +#include <linux/clocksource.h> +#include <linux/clockchips.h> + +#include <mach/regs-sys-ns921x.h> +#include <mach/irqs.h> + +#include "irq.h" +#include "processor-ns921x.h" + +#define TIMER_CLOCKSOURCE 0 +#define TIMER_CLOCKEVENT 1 +static u32 latch; + +static cycle_t ns921x_clocksource_read(void) +{ + return __raw_readl(SYS_TRC(TIMER_CLOCKSOURCE)); +} + +static struct clocksource ns921x_clocksource = { + .name = "ns921x-timer" __stringify(TIMER_CLOCKSOURCE), + .rating = 300, + .read = ns921x_clocksource_read, + .mask = CLOCKSOURCE_MASK(32), + .shift = 20, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static void ns921x_clockevent_setmode(enum clock_event_mode mode, + struct clock_event_device *clk) +{ + u32 oldtc, tc = __raw_readl(SYS_TC(TIMER_CLOCKEVENT)); + oldtc = tc; + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + __raw_writel(latch, SYS_TRCC(TIMER_CLOCKEVENT)); + REGSET(tc, SYS_TCx, RELENBL, EN); + REGSET(tc, SYS_TCx, INTSEL, EN); + REGSET(tc, SYS_TCx, TE, EN); + break; + + case CLOCK_EVT_MODE_ONESHOT: + REGSET(tc, SYS_TCx, RELENBL, DIS); + REGSET(tc, SYS_TCx, INTSEL, EN); + REGSET(tc, SYS_TCx, TE, DIS); + break; + + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + default: + REGSET(tc, SYS_TCx, TE, DIS); + break; + } + + /* ack an possibly pending irq + * This might stuck the irq priority encoder, but only until the next + * timer irq ... */ + if (REGGET(tc, SYS_TCx, TE) == SYS_TCx_TE_DIS && + REGGET(oldtc, SYS_TCx, TE) == SYS_TCx_TE_EN) { + REGSETIM(tc, SYS_TCx, INTCLR, 1); + __raw_writel(tc, SYS_TC(TIMER_CLOCKEVENT)); + REGSETIM(tc, SYS_TCx, INTCLR, 0); + } + + __raw_writel(tc, SYS_TC(TIMER_CLOCKEVENT)); +} + +static int ns921x_clockevent_setnextevent(unsigned long evt, + struct clock_event_device *clk) +{ + u32 tc = __raw_readl(SYS_TC(TIMER_CLOCKEVENT)); + + if (REGGET(tc, SYS_TCx, TE)) { + REGSET(tc, SYS_TCx, TE, DIS); + __raw_writel(tc, SYS_TC(TIMER_CLOCKEVENT)); + } + + REGSET(tc, SYS_TCx, TE, EN); + + __raw_writel(evt, SYS_TRCC(TIMER_CLOCKEVENT)); + + __raw_writel(tc, SYS_TC(TIMER_CLOCKEVENT)); + + return 0; +} + +static struct clock_event_device ns921x_clockevent_device = { + .name = "ns921x-timer" __stringify(TIMER_CLOCKEVENT), + .shift = 20, + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = ns921x_clockevent_setmode, + .set_next_event = ns921x_clockevent_setnextevent, +}; + +static irqreturn_t ns921x_clockevent_handler(int irq, void *dev_id) +{ + int timerno = irq - IRQ_NS921X_TIMER0; + u32 tc; + + struct clock_event_device *evt = &ns921x_clockevent_device; + + /* clear irq */ + tc = __raw_readl(SYS_TC(timerno)); + if (REGGET(tc, SYS_TCx, RELENBL) == SYS_TCx_RELENBL_DIS) { + REGSET(tc, SYS_TCx, TE, DIS); + __raw_writel(tc, SYS_TC(timerno)); + } + REGSETIM(tc, SYS_TCx, INTCLR, 1); + __raw_writel(tc, SYS_TC(timerno)); + REGSETIM(tc, SYS_TCx, INTCLR, 0); + __raw_writel(tc, SYS_TC(timerno)); + + evt->event_handler(evt); + + return IRQ_HANDLED; +} + +static struct irqaction ns921x_clockevent_action = { + .name = "ns921x-timer" __stringify(TIMER_CLOCKEVENT), + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .handler = ns921x_clockevent_handler, +}; + +static void __init ns921x_timer_init(void) +{ + int tc; + + tc = __raw_readl(SYS_TC(TIMER_CLOCKSOURCE)); + if (REGGET(tc, SYS_TCx, TE)) { + REGSET(tc, SYS_TCx, TE, DIS); + __raw_writel(tc, SYS_TC(TIMER_CLOCKSOURCE)); + } + + __raw_writel(0, SYS_TRC(TIMER_CLOCKSOURCE)); + + REGSET(tc, SYS_TCx, TE, EN); + REGSET(tc, SYS_TCx, DEBUG, STOP); + REGSET(tc, SYS_TCx, TCS, 2AHB); + REGSET(tc, SYS_TCx, MODE, INTERNAL); + REGSET(tc, SYS_TCx, INTSEL, DIS); + REGSET(tc, SYS_TCx, UPDOWN, UP); + REGSET(tc, SYS_TCx, BITTIMER, 32); + REGSET(tc, SYS_TCx, RELENBL, EN); + + __raw_writel(tc, SYS_TC(TIMER_CLOCKSOURCE)); + + ns921x_clocksource.mult = clocksource_hz2mult(ns921x_ahbclock() * 2, + ns921x_clocksource.shift); + + clocksource_register(&ns921x_clocksource); + + latch = SH_DIV(ns921x_ahbclock() * 2, HZ, 0); + + tc = __raw_readl(SYS_TC(TIMER_CLOCKEVENT)); + REGSET(tc, SYS_TCx, TE, DIS); + REGSET(tc, SYS_TCx, DEBUG, STOP); + REGSET(tc, SYS_TCx, TCS, 2AHB); + REGSET(tc, SYS_TCx, MODE, INTERNAL); + REGSET(tc, SYS_TCx, INTSEL, DIS); + REGSET(tc, SYS_TCx, UPDOWN, DOWN); + REGSET(tc, SYS_TCx, BITTIMER, 32); + REGSET(tc, SYS_TCx, RELENBL, EN); + __raw_writel(tc, SYS_TC(TIMER_CLOCKEVENT)); + + ns921x_clockevent_device.mult = div_sc(ns921x_ahbclock() * 2, + NSEC_PER_SEC, ns921x_clockevent_device.shift); + ns921x_clockevent_device.max_delta_ns = + clockevent_delta2ns(-1, &ns921x_clockevent_device); + ns921x_clockevent_device.min_delta_ns = + clockevent_delta2ns(1, &ns921x_clockevent_device); + + ns921x_clockevent_device.cpumask = cpumask_of_cpu(0); + clockevents_register_device(&ns921x_clockevent_device); + + setup_irq(IRQ_NS921X_TIMER0 + TIMER_CLOCKEVENT, + &ns921x_clockevent_action); +} + +struct sys_timer ns921x_timer = { + .init = ns921x_timer_init, +}; diff --git a/arch/arm/mach-ns9xxx/time-ns9360.c b/arch/arm/mach-ns9xxx/time-ns9360.c index a63424d083d9..553617eba15a 100644 --- a/arch/arm/mach-ns9xxx/time-ns9360.c +++ b/arch/arm/mach-ns9xxx/time-ns9360.c @@ -15,11 +15,12 @@ #include <linux/clocksource.h> #include <linux/clockchips.h> -#include <mach/processor-ns9360.h> #include <mach/regs-sys-ns9360.h> #include <mach/irqs.h> #include <mach/system.h> -#include "generic.h" + +#include "irq.h" +#include "processor-ns9360.h" #define TIMER_CLOCKSOURCE 0 #define TIMER_CLOCKEVENT 1 |