diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/Kconfig linux-2.6.27.8/arch/arm/Kconfig --- linux-2.6.27.8-base/arch/arm/Kconfig 2009-01-08 11:42:27.000000000 -0800 +++ linux-2.6.27.8/arch/arm/Kconfig 2009-01-08 12:02:03.000000000 -0800 @@ -436,6 +436,14 @@ Orion-1 (5181), Orion-VoIP (5181L), Orion-NAS (5182), Orion-2 (5281). +config ARCH_LPC32XX + bool "NXP LPC32XX" + select HAVE_IDE + select ARM_AMBA + select USB_ARCH_HAS_OHCI + help + Support for the NXP LPC32XX family or processors + config ARCH_PNX4008 bool "Philips Nexperia PNX4008 Mobile" select HAVE_CLK @@ -592,6 +600,8 @@ source "arch/arm/mach-s3c2443/Kconfig" endif +source "arch/arm/mach-lpc32xx/Kconfig" + source "arch/arm/mach-lh7a40x/Kconfig" source "arch/arm/mach-imx/Kconfig" diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/arch-lpc32xx.c linux-2.6.27.8/arch/arm/mach-lpc32xx/arch-lpc32xx.c --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/arch-lpc32xx.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/arch-lpc32xx.c 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,621 @@ +/* + * linux/arch/arm/mach-lpc32xx/arch-lpc32xx.c + * + * Copyright (C) 2008 NXP Semiconductors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "sys-lpc32xx.h" + +#define CLKPWR_IOBASE io_p2v(CLK_PM_BASE) +#define GPIO_IOBASE io_p2v(GPIO_BASE) + +#if defined(CONFIG_LPC32XX_WATCHDOG) +/* + * Watchdog timer resources + */ +static struct resource watchdog_resources[] = { + [0] = { + .start = WDTIM_BASE, + .end = WDTIM_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, +}; +static struct platform_device watchdog_device = { + .name = "watchdog", + .id = -1, + .num_resources = ARRAY_SIZE(watchdog_resources), + .resource = watchdog_resources, +}; +#endif + +#if defined (CONFIG_RTC_DRV_LPC32XX) +/* + * RTC resources + */ +static struct resource rtc_resources[] = { + [0] = { + .start = RTC_BASE, + .end = RTC_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_RTC, + .flags = IORESOURCE_IRQ, + }, +}; +static struct platform_device rtc_device = { + .name = "rtc-lpc32xx", + .id = -1, + .num_resources = ARRAY_SIZE(rtc_resources), + .resource = rtc_resources, +}; +#endif + +#if defined (CONFIG_TOUCHSCREEN_LPC32XX) +/* + * Touchscreen resources + */ +static struct resource tsc_resources[] = { + [0] = { + .start = ADC_BASE, + .end = ADC_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_TS_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; +static struct platform_device tsc_device = { + .name = "lpc32xx-ts", + .id = -1, + .num_resources = ARRAY_SIZE(tsc_resources), + .resource = tsc_resources, +}; +#endif + +#if defined (CONFIG_MACH_LPC32XX_I2C0_ENABLE) || defined (CONFIG_MACH_LPC32XX_I2C1_ENABLE) || defined (CONFIG_MACH_LPC32XX_USBOTG_I2C_ENABLE) +/* + * I2C resources + */ +static void clock_get_name(char *name, int id) +{ + snprintf(name, 10, "i2c%d_ck", id); +} +static int set_clock_run(struct platform_device *pdev) +{ + struct clk *clk; + char name[10]; + int retval = 0; + + clock_get_name(name, pdev->id); + clk = clk_get(&pdev->dev, name); + if (!IS_ERR(clk)) { + clk_set_rate(clk, 1); + clk_put(clk); + } else + retval = -ENOENT; + + return retval; +} +static int set_clock_stop(struct platform_device *pdev) +{ + struct clk *clk; + char name[10]; + int retval = 0; + + clock_get_name(name, pdev->id); + clk = clk_get(&pdev->dev, name); + if (!IS_ERR(clk)) { + clk_set_rate(clk, 0); + clk_put(clk); + } else + retval = -ENOENT; + + return retval; +} +static int i2c_lpc32xx_suspend(struct platform_device *pdev, pm_message_t state) +{ + int retval = 0; +#ifdef CONFIG_PM + retval = set_clock_run(pdev); +#endif + return retval; +} +static int i2c_lpc32xx_resume(struct platform_device *pdev) +{ + int retval = 0; +#ifdef CONFIG_PM + retval = set_clock_run(pdev); +#endif + return retval; +} +static u32 calculate_input_freq(struct platform_device *pdev) +{ + struct clk *clk; + char name[10]; + u32 clkrate = MAIN_OSC_FREQ; + + clock_get_name(name, pdev->id); + clk = clk_get(&pdev->dev, name); + if (!IS_ERR(clk)) { + /* Just get the parent rate, as the I2C driver hasn't + actually enabled the clock prior to querying it, so + it will always return 0! */ + clkrate = clk_get_rate(clk->parent); + clk_put(clk); + } + + /* Unlike other drivers, the PNX driver requires the rate + in MHz */ + clkrate = clkrate / (1000 * 1000); + + return clkrate; +} +#endif +#if defined (CONFIG_MACH_LPC32XX_I2C0_ENABLE) +static struct i2c_pnx_algo_data lpc32xx_algo_data0 = { + .base = I2C1_BASE, + .irq = IRQ_I2C_1, +}; +static struct i2c_adapter lpc32xx_adapter0 = { + .name = I2C_CHIP_NAME "0", + .algo_data = &lpc32xx_algo_data0, +}; +static struct i2c_pnx_data i2c0_data = { + .suspend = i2c_lpc32xx_suspend, + .resume = i2c_lpc32xx_resume, + .calculate_input_freq = calculate_input_freq, + .set_clock_run = set_clock_run, + .set_clock_stop = set_clock_stop, + .adapter = &lpc32xx_adapter0, +}; +static struct platform_device i2c0_device = { + .name = "pnx-i2c", + .id = 0, + .dev = { + .platform_data = &i2c0_data, + }, +}; +#endif +#if defined (CONFIG_MACH_LPC32XX_I2C1_ENABLE) +static struct i2c_pnx_algo_data lpc32xx_algo_data1 = { + .base = I2C2_BASE, + .irq = IRQ_I2C_2, +}; +static struct i2c_adapter lpc32xx_adapter1 = { + .name = I2C_CHIP_NAME "1", + .algo_data = &lpc32xx_algo_data1, +}; +static struct i2c_pnx_data i2c1_data = { + .suspend = i2c_lpc32xx_suspend, + .resume = i2c_lpc32xx_resume, + .calculate_input_freq = calculate_input_freq, + .set_clock_run = set_clock_run, + .set_clock_stop = set_clock_stop, + .adapter = &lpc32xx_adapter1, +}; +static struct platform_device i2c1_device = { + .name = "pnx-i2c", + .id = 1, + .dev = { + .platform_data = &i2c1_data, + }, +}; +#endif +#if defined (CONFIG_MACH_LPC32XX_USBOTG_I2C_ENABLE) +static struct i2c_pnx_algo_data lpc32xx_algo_data2 = { + .base = OTG_I2C_BASE, + .irq = IRQ_USB_I2C, +}; +static struct i2c_adapter lpc32xx_adapter2 = { + .name = "USB-I2C", + .algo_data = &lpc32xx_algo_data2, +}; +static struct i2c_pnx_data i2c2_data = { + .suspend = i2c_lpc32xx_suspend, + .resume = i2c_lpc32xx_resume, + .calculate_input_freq = calculate_input_freq, + .set_clock_run = set_clock_run, + .set_clock_stop = set_clock_stop, + .adapter = &lpc32xx_adapter2, +}; +static struct platform_device i2c2_device = { + .name = "pnx-i2c", + .id = 2, + .dev = { + .platform_data = &i2c2_data, + }, +}; +#endif + +#if defined(CONFIG_MTD_NAND_SLC_LPC32XX) +/* + * SLC NAND resources + */ +static struct resource slc_nand_resources[] = { + [0] = { + .start = SLC_BASE, + .end = SLC_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + + [1] = { + .start = IRQ_FLASH, + .end = IRQ_FLASH, + .flags = IORESOURCE_IRQ, + }, + +}; +static struct platform_device slc_nand_device = { + .name = "lpc32xx-nand", + .id = 0, + .dev = { + .platform_data = &lpc32xx_nandcfg, + }, + .num_resources = ARRAY_SIZE(slc_nand_resources), + .resource = slc_nand_resources, +}; +#endif + +#if defined(CONFIG_KEYBOARD_LPC32XX) +static struct resource kscan_resources[] = { + [0] = { + .start = KSCAN_BASE, + .end = KSCAN_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_KEY, + .end = IRQ_KEY, + .flags = IORESOURCE_IRQ, + }, + +}; +static struct platform_device kscan_device = { + .name = "lpc32xx_keys", + .id = 0, + .dev = { + .platform_data = &lpc32xx_kscancfg, + }, + .num_resources = ARRAY_SIZE(kscan_resources), + .resource = kscan_resources, +}; +#endif + +#if defined (CONFIG_LPC32XX_MII) +static struct resource net_resources[] = { + [0] = { + .start = ETHERNET_BASE, + .end = ETHERNET_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + + [1] = { + .start = IRQ_ETHERNET, + .end = IRQ_ETHERNET, + .flags = IORESOURCE_IRQ, + }, + +}; +#endif + +#if defined (CONFIG_LPC32XX_MII) +static u64 lpc32xx_mac_dma_mask = 0xffffffffUL; +static struct platform_device net_device = { + .name = "lpc32xx-net", + .id = 0, + .dev = { + .dma_mask = &lpc32xx_mac_dma_mask, + .coherent_dma_mask = 0xffffffffUL, + .platform_data = &lpc32xx_netdata, + }, + .num_resources = ARRAY_SIZE(net_resources), + .resource = net_resources, +}; +#endif + +#if defined(CONFIG_SPI_LPC32XX) +#if defined(CONFIG_MACH_LPC32XX_SSP0_ENABLE) +static struct resource ssp0_resources[] = { + [0] = { + .start = SSP0_BASE, + .end = SSP0_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_SSP0, + .end = IRQ_SSP0, + .flags = IORESOURCE_IRQ, + }, + +}; +static struct platform_device ssp0_device = { + .name = "spi_lpc32xx", + .id = 0, + .dev = { + .platform_data = &lpc32xx_spi1data, + }, + .num_resources = ARRAY_SIZE(ssp0_resources), + .resource = ssp0_resources, +}; +#endif +#if defined(CONFIG_MACH_LPC32XX_SSP1_ENABLE) +static struct resource ssp1_resources[] = { + [0] = { + .start = SSP1_BASE, + .end = SSP1_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_SSP1, + .end = IRQ_SSP1, + .flags = IORESOURCE_IRQ, + }, + +}; +static struct platform_device ssp1_device = { + .name = "spi_lpc32xx", + .id = 1, + .dev = { + .platform_data = &lpc32xx_spi2data, + }, + .num_resources = ARRAY_SIZE(ssp1_resources), + .resource = ssp1_resources, +}; +#endif +#endif + +#if defined (CONFIG_USB_OHCI_HCD) +/* The dmamask must be set for OHCI to work */ +static u64 ohci_dmamask = ~(u32) 0; +static struct resource ohci_resources[] = { + { + .start = IO_ADDRESS(USB_BASE), + .end = IO_ADDRESS(USB_BASE + 0x100), + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_USB_HOST, + .flags = IORESOURCE_IRQ, + }, +}; +static struct platform_device ohci_device = { + .name = "usb-ohci", + .id = -1, + .dev = { + .dma_mask = &ohci_dmamask, + .coherent_dma_mask = 0xFFFFFFFF, + }, + .num_resources = ARRAY_SIZE(ohci_resources), + .resource = ohci_resources, +}; +#endif + +#if defined(CONFIG_USB_GADGET_LPC32XX) +/* The dmamask must be set for OHCI to work */ +static u64 usbd_dmamask = ~(u32) 0; +static struct resource usbd_resources[] = { + { + .start = IO_ADDRESS(USB_BASE), + .end = IO_ADDRESS(USB_BASE + SZ_4K), + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_USB_DEV_LP, + .flags = IORESOURCE_IRQ, + }, { + .start = IRQ_USB_DEV_HP, + .flags = IORESOURCE_IRQ, + }, { + .start = IRQ_USB_DEV_DMA, + .flags = IORESOURCE_IRQ, + }, { + .start = IRQ_USB_OTG_ATX, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device usbd_device = { + .name = "lpc32xx_udc", + .id = -1, + .dev = { + .dma_mask = &usbd_dmamask, + .coherent_dma_mask = 0xFFFFFFFF, + }, + .num_resources = ARRAY_SIZE(usbd_resources), + .resource = usbd_resources, +}; +#endif + +#if defined (CONFIG_MMC_ARMMMCI) +/* + * SD card controller resources + */ +struct amba_device mmc_device = { + .dev = { + .coherent_dma_mask = ~0, + .bus_id = "dev:31", + .platform_data = &lpc32xx_plat_data, + }, + .res = { + .start = SD_BASE, + .end = (SD_BASE + SZ_4K - 1), + .flags = IORESOURCE_MEM, + }, + .dma_mask = ~0, + .irq = {IRQ_SD0, IRQ_SD1}, +}; +#endif + +#if defined (CONFIG_FB_ARMCLCD) +struct amba_device clcd_device = { + .dev = { + .coherent_dma_mask = ~0, + .bus_id = "dev:20", + .platform_data = &lpc32xx_clcd_data, + }, + .res = { + .start = LCD_BASE, + .end = (LCD_BASE + SZ_4K - 1), + .flags = IORESOURCE_MEM, + }, + .dma_mask = ~0, + .irq = {IRQ_LCD, NO_IRQ}, +}; +#endif + +static struct platform_device* lpc32xx_devs[] __initdata = { + &serial_std_platform_device, + &serial_hspd_platform_device, +#if defined (CONFIG_RTC_DRV_LPC32XX) + &rtc_device, +#endif +#if defined(CONFIG_SPI_LPC32XX) +#if defined(CONFIG_MACH_LPC32XX_SSP0_ENABLE) + &ssp0_device, +#endif +#if defined(CONFIG_MACH_LPC32XX_SSP1_ENABLE) + &ssp1_device, +#endif +#endif +#if defined (CONFIG_MACH_LPC32XX_I2C0_ENABLE) + &i2c0_device, +#endif +#if defined (CONFIG_MACH_LPC32XX_I2C1_ENABLE) + &i2c1_device, +#endif +#if defined (CONFIG_MACH_LPC32XX_USBOTG_I2C_ENABLE) + &i2c2_device, +#endif +#if defined(CONFIG_MTD_NAND_SLC_LPC32XX) + &slc_nand_device, +#endif +#if defined(CONFIG_TOUCHSCREEN_LPC32XX) + &tsc_device, +#endif +#if defined(CONFIG_KEYBOARD_LPC32XX) + &kscan_device, +#endif +#if defined (CONFIG_LPC32XX_MII) + &net_device, +#endif +#if defined(CONFIG_USB_OHCI_HCD) + &ohci_device, +#endif +#if defined(CONFIG_LPC32XX_WATCHDOG) + &watchdog_device, +#endif +#if defined(CONFIG_USB_GADGET_LPC32XX) + &usbd_device, +#endif +}; + +void __init lpc32xx_init (void) +{ + u32 tmp = 0; + + /* Setup clocks before anything else! */ + clk_init(); + + /* Pre-initialize serial ports */ + serial_init(); + + platform_add_devices (lpc32xx_devs, ARRAY_SIZE (lpc32xx_devs)); + +#if defined(CONFIG_MMC_ARMMMCI) + /* Enable SD card clock so AMBA driver will work correctly. The + AMBA driver needs the clock before the SD card controller + driver initializes it. The clock will turn off once the driver + has been initialized. */ + tmp = __raw_readl(CLKPWR_MS_CTRL(CLKPWR_IOBASE)); + tmp |= CLKPWR_MSCARD_SDCARD_EN | CLKPWR_MSCARD_MSDIO_PU_EN; + __raw_writel(tmp, CLKPWR_MS_CTRL(CLKPWR_IOBASE)); + + amba_device_register(&mmc_device, &iomem_resource); +#endif + +#if defined(CONFIG_FB_ARMCLCD) + /* Enable LCD clock so AMBA driver will work correctly. The + AMBA driver needs the clock before the LCD driver initializes it. + The clock will turn off once the driver has been initialized. */ + tmp = __raw_readl(CLKPWR_LCDCLK_CTRL(CLKPWR_IOBASE)); + tmp |= CLKPWR_LCDCTRL_CLK_EN; + __raw_writel(tmp, CLKPWR_LCDCLK_CTRL(CLKPWR_IOBASE)); + + amba_device_register(&clcd_device, &iomem_resource); +#endif +} + +static struct map_desc lpc32xx_io_desc[] __initdata = { + { + .virtual = io_p2v(AHB0_START), + .pfn = __phys_to_pfn(AHB0_START), + .length = AHB0_SIZE, + .type = MT_DEVICE + }, + { + .virtual = io_p2v(AHB1_START), + .pfn = __phys_to_pfn(AHB1_START), + .length = AHB1_SIZE, + .type = MT_DEVICE + }, + { + .virtual = io_p2v(FABAPB_START), + .pfn = __phys_to_pfn(FABAPB_START), + .length = FABAPB_SIZE, + .type = MT_DEVICE + }, + { + .virtual = io_p2v(IRAM_BASE), + .pfn = __phys_to_pfn(IRAM_BASE), + .length = (SZ_64K * 4), + .type = MT_DEVICE + }, +}; + +void __init lpc32xx_map_io(void) +{ + iotable_init (lpc32xx_io_desc, ARRAY_SIZE (lpc32xx_io_desc)); +} + diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/board-phy3250.c linux-2.6.27.8/arch/arm/mach-lpc32xx/board-phy3250.c --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/board-phy3250.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/board-phy3250.c 2009-01-08 16:36:48.000000000 -0800 @@ -0,0 +1,606 @@ +/* + * linux/arch/arm/mach-lpc32xx/board-phy3250.c + * + * Copyright (C) 2008 NXP Semiconductors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "sys-lpc32xx.h" + +#define BOARDDEBUG + +/* + * Structure used to define the hardware for the Phytec board. This + * is obtained from index (PHY3250_SEEPROM_CFGOFS) in the AT25 serial + * EEPROM. The .fieldval value must be checked for the correct value + * (PHY_HW_VER_VAL) or the sturcture is invalid. + */ +typedef struct +{ + u32 dramcfg; /* DRAM config word */ + u32 syscfg; /* Configuration word */ + /* MAC address, use lower 6 bytes only, index 0 is first byte */ + u8 mac[8]; /* Only the first 6 are used */ + u32 rsvd [5]; /* Reserved, must be 0 */ + u32 fieldvval; /* Must be PHY_HW_VER_VAL */ +} PHY_HW_T; +static PHY_HW_T phyhwdata; + +/* + * Serial EEPROM support + */ +#define PHY_HW_VER_VAL 0x000A3250 +#define SEEPROM_READ 0x03 +#define PHY3250_SEEPROM_SIZE 0x8000 +#define PHY3250_SEEPROM_CFGOFS (PHY3250_SEEPROM_SIZE - 0x100) +#define AT25256_PAGE_SIZE 64 + +/* + * Board specific key scanner driver data + */ +#define KMATRIX_SIZE 1 +static int lpc32xx_keymaps[] = +{ + KEY_1, /* 1, 1 */ +}; +struct lpc32XX_kscan_cfg lpc32xx_kscancfg = { + .matrix_sz = KMATRIX_SIZE, + .keymap = lpc32xx_keymaps, + /* About a 30Hz scan rate based on a 32KHz clock */ + .deb_clks = 3, + .scan_delay = 34, +}; + +/* + * Returns 0 when card is removed, !0 when installed + */ +unsigned int mmc_status(struct device *dev) +{ + u32 tmp, inserted = 0; + + tmp = __raw_readl(GPIO_P3_INP_STATE(GPIO_IOBASE)) & + INP_STATE_GPIO_01; + if (tmp == 0) + { + inserted = 1; + } + + return inserted; +} + +/* + * Enable or disable SD slot power + */ +void mmc_power_enable(int enable) +{ + if (enable != 0) + { + __raw_writel(OUTP_STATE_GPO(5), GPIO_P3_OUTP_SET(GPIO_IOBASE)); + } + else + { + __raw_writel(OUTP_STATE_GPO(5), GPIO_P3_OUTP_CLR(GPIO_IOBASE)); + } +} + +/* + * Board specific MMC driver data + */ +struct mmc_platform_data lpc32xx_plat_data = { + .ocr_mask = MMC_VDD_30_31|MMC_VDD_31_32|MMC_VDD_32_33|MMC_VDD_33_34, + .status = mmc_status, +}; + +/* + * Board specific NAND setup data + */ +static int nandwp_enable(int enable) +{ + if (enable != 0) + { + __raw_writel(OUTP_STATE_GPO(19), GPIO_P3_OUTP_CLR(GPIO_IOBASE)); + } + else + { + __raw_writel(OUTP_STATE_GPO(19), GPIO_P3_OUTP_SET(GPIO_IOBASE)); + } + + return 1; +} +#define BLK_SIZE (512 * 32) +static struct mtd_partition __initdata phy3250_nand_partition[] = { + { + .name = "phy3250-boot", + .offset = 0, + .size = (BLK_SIZE * 90) + }, + { + .name = "phy3250-ubt-prms", + .offset = (BLK_SIZE * 90), + .size = (BLK_SIZE * 10) + }, + { + .name = "phy3250-kernel", + .offset = (BLK_SIZE * 100), + .size = (BLK_SIZE * 256) + }, + { + .name = "phy3250-rootfs", + .offset = (BLK_SIZE * 356), + .size = MTDPART_SIZ_FULL + }, +}; +static struct mtd_partition * __init phy3250_nand_partitions(int size, int *num_partitions) +{ + *num_partitions = ARRAY_SIZE(phy3250_nand_partition); + return phy3250_nand_partition; +} +struct lpc32XX_nand_cfg lpc32xx_nandcfg = +{ + .wdr_clks = 3, + .wwidth = 28571428, + .whold = 100000000, + .wsetup = 66666666, + .rdr_clks = 3, + .rwidth = 28571428, + .rhold = 100000000, + .rsetup = 66666666, + .use16bus = 0, + .enable_write_prot = nandwp_enable, + .partition_info = phy3250_nand_partitions, +}; + +/* + * Board specific LCD setup and functions + */ +#if defined (CONFIG_PHY3250_LCD_PANEL) +#if defined (CONFIG_PHY3250_QVGA_PANEL_1307_0) || defined (CONFIG_PHY3250_QVGA_PANEL_1307_1) +/* + * Support for QVGA portrait panel from Phytec + */ +static struct clcd_panel conn_lcd_panel = { + .mode = { + .name = "QVGA portrait", + .refresh = 60, + .xres = 240, + .yres = 320, + .pixclock = 191828, + .left_margin = 22, + .right_margin = 11, + .upper_margin = 2, + .lower_margin = 1, + .hsync_len = 5, + .vsync_len = 2, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + }, + .width = -1, + .height = -1, + .tim2 = (CLCDC_LCDTIMING2_IVS | CLCDC_LCDTIMING2_IHS), + .cntl = (CNTL_BGR | CLCDC_LCDCTRL_TFT | CNTL_LCDVCOMP(1) | + CLCDC_LCDCTRL_BPP16_565), + .bpp = 16, +}; +#define PANEL_SIZE (3 * SZ_64K) +#endif +static int lpc32xx_clcd_setup(struct clcd_fb *fb) +{ +#if defined(CONFIG_MACH_LPC32XX_IRAM_FOR_CLCD) + fb->fb.screen_base = (void *) io_p2v(IRAM_BASE); + fb->fb.fix.smem_start = (dma_addr_t) IRAM_BASE; +#else + dma_addr_t dma; + + fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, + PANEL_SIZE, &dma, GFP_KERNEL); + fb->fb.fix.smem_start = dma; +#endif + + if (!fb->fb.screen_base) { + printk(KERN_ERR "CLCD: unable to map framebuffer\n"); + return -ENOMEM; + } + + fb->fb.fix.smem_len = PANEL_SIZE; + fb->panel = &conn_lcd_panel; + + return 0; +} +static int lpc32xx_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma) +{ +#if defined(CONFIG_MACH_LPC32XX_IRAM_FOR_CLCD) + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, + (vma->vm_end - vma->vm_start), vma->vm_page_prot)) { + return -EAGAIN; + } + + return 0; + +#else + return dma_mmap_writecombine(&fb->dev->dev, vma, + fb->fb.screen_base, + fb->fb.fix.smem_start, + fb->fb.fix.smem_len); +#endif +} +static void lpc32xx_clcd_remove(struct clcd_fb *fb) +{ +#if !defined(CONFIG_MACH_LPC32XX_IRAM_FOR_CLCD) + dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len, + fb->fb.screen_base, fb->fb.fix.smem_start); +#endif +} +void clcd_disable(struct clcd_fb *fb) +{ + /* Disable the backlight */ +#if defined (CONFIG_PHY3250_QVGA_PANEL_1307_0) + __raw_writel(OUTP_STATE_GPO(4), GPIO_P3_OUTP_SET(GPIO_IOBASE)); +#elif defined (CONFIG_PHY3250_QVGA_PANEL_1307_1) + __raw_writel(OUTP_STATE_GPO(4), GPIO_P3_OUTP_CLR(GPIO_IOBASE)); +#endif + + /* Disable the LCD power */ + __raw_writel(OUTP_STATE_GPO(0), GPIO_P3_OUTP_CLR(GPIO_IOBASE)); +} +void clcd_enable(struct clcd_fb *fb) +{ + /* Enable the backlight */ +#if defined (CONFIG_PHY3250_QVGA_PANEL_1307_0) + __raw_writel(OUTP_STATE_GPO(4), GPIO_P3_OUTP_CLR(GPIO_IOBASE)); +#elif defined (CONFIG_PHY3250_QVGA_PANEL_1307_1) + __raw_writel(OUTP_STATE_GPO(4), GPIO_P3_OUTP_SET(GPIO_IOBASE)); +#endif + + /* Enable the LCD power */ + __raw_writel(OUTP_STATE_GPO(0), GPIO_P3_OUTP_SET(GPIO_IOBASE)); +} +struct clcd_board lpc32xx_clcd_data = { + .name = "Phytec LCD", + .check = clcdfb_check, + .decode = clcdfb_decode, + .disable = clcd_disable, + .enable = clcd_enable, + .setup = lpc32xx_clcd_setup, + .mmap = lpc32xx_clcd_mmap, + .remove = lpc32xx_clcd_remove, +}; +#endif + +/* + * Network configuration structure + */ +#if defined (CONFIG_LPC32XX_MII) +static int return_mac_address(u8 *mac) +{ + int ret = 0; + int i; + + if (phyhwdata.fieldvval != PHY_HW_VER_VAL) + { + /* Field has garbage in it */ + printk(KERN_ERR "Invalid ethernet MAC address\n"); + ret = -ENODEV; + } + + /* Use MAC address from hardware descriptor */ + for (i = 0; i < 6; i++) + { + mac [i] = phyhwdata.mac [i]; + } + + return ret; +} + +struct lpc32xx_net_cfg lpc32xx_netdata = +{ + .get_mac_addr = &return_mac_address, + .phy_irq = -1, + .phy_mask = 0xFFFFFFF0, + +}; +#endif + +static void phy3250_spi_cs_setup(int cs) +{ + /* Setup SPI CS0 as an output on GPIO5 */ + __raw_writel((1 << 5), GPIO_P2_MUX_CLR(GPIO_IOBASE)); + + /* Set chip select high */ + __raw_writel(OUTP_STATE_GPIO(5), + GPIO_P3_OUTP_SET(GPIO_IOBASE)); +} +static int phy3250_spi_cs_set(int cs, int state) +{ + if (cs == 0) + { + if (state != 0) + { + /* Set chip select high */ + __raw_writel(OUTP_STATE_GPIO(5), + GPIO_P3_OUTP_SET(GPIO_IOBASE)); + } + else + { + /* Set chip select low */ + __raw_writel(OUTP_STATE_GPIO(5), + GPIO_P3_OUTP_CLR(GPIO_IOBASE)); + } + } + else + { + /* Invalid chip select */ + return -ENODEV; + } + + return 0; +} + +#if defined (CONFIG_MACH_LPC32XX_SSP0_ENABLE) +struct lpc32xx_spi_cfg lpc32xx_spi1data = +{ + .num_cs = 1, /* Only 1 chip select */ + .spi_cs_setup = &phy3250_spi_cs_setup, + .spi_cs_set = &phy3250_spi_cs_set, +}; + +/* AT25 driver registration */ +static int __init phy3250_spi_eeprom_register(void) +{ + static struct spi_eeprom eeprom = + { + .name = "at25256a", + .byte_len = 0x8000, + .page_size = AT25256_PAGE_SIZE, + .flags = EE_ADDR2, + }; + struct spi_board_info info = + { + .modalias = "at25", + .max_speed_hz = 5000000, + .bus_num = 0, + .chip_select = 0, + .platform_data = &eeprom, + }; + + return spi_register_board_info(&info, 1); +} +arch_initcall(phy3250_spi_eeprom_register); +#endif + +#if defined(CONFIG_RTC_DRV_PCF8563) +static struct i2c_board_info __initdata phy3250_i2c_board_info [] = { + { + I2C_BOARD_INFO("rtc-pcf8563", 0x51), + }, +}; +#endif + +/* + * Load the board hardware descriptor from the serial EEPROM + */ +static void __init phy3250_load_hw_desc(void) +{ + u32 svclk, tmp, addr; + int i, len; + u8 *p8, cmd [4], in [4]; + u32 sspiobase = io_p2v(SSP0_BASE); + + /* Enable SSP0 clock */ + svclk = __raw_readl(CLKPWR_SSP_CLK_CTRL(CLKPWR_IOBASE)); + __raw_writel((svclk | CLKPWR_SSPCTRL_SSPCLK0_EN), + CLKPWR_SSP_CLK_CTRL(CLKPWR_IOBASE)); + + /* Setup SSP0 chip select mux */ + phy3250_spi_cs_setup(0); + phy3250_spi_cs_set(0, 1); + + /* Initial setup of SSP0 for transfer with AT25 serial EEPROM */ + __raw_writel(0, SSP_ICR(sspiobase)); + __raw_writel((SSP_ICR_RORIC | SSP_ICR_RTIC), SSP_IMSC(sspiobase)); + + /* Setup default SPI mode at about 5MHz */ + __raw_writel((SSP_CR0_DSS(8) | SSP_CR0_FRF_SPI | SSP_CR0_CPOL(0) | + SSP_CR0_CPHA(0) | SSP_CR0_SCR(40)), SSP_CR0(sspiobase)); + __raw_writel(SSP_CR1_SSP_ENABLE, SSP_CR1(sspiobase)); + __raw_writel(SSP_CPSR_CPDVSR(40), SSP_CPSR(sspiobase)); + + /* Flush RX FIFO */ + while (__raw_readl(SSP_SR(sspiobase)) & SSP_SR_RNE) + { + tmp = __raw_readl(SSP_DATA(sspiobase)); + } + + len = sizeof (phyhwdata); + p8 = (u8 *) &phyhwdata; + addr = PHY3250_SEEPROM_CFGOFS; + while (len > 0) + { + /* Toggle chip select low */ + phy3250_spi_cs_set(0, 0); + + /* Issue read command and address for 1 byte */ + cmd[0] = SEEPROM_READ; + cmd[1] = ((addr >> 8) & 0xFF); + cmd[2] = ((addr >> 0) & 0xFF); + cmd[3] = 0xFF; + for (i = 0; i < 4; i++) + { + __raw_writel((u32) cmd [i], SSP_DATA(sspiobase)); + } + + /* Save 4 bytes */ + i = 0; + while (i < 4) + { + if (__raw_readl(SSP_SR(sspiobase)) & SSP_SR_RNE) + { + in [i] = (u8) __raw_readl(SSP_DATA(sspiobase)); + i++; + } + } + + /* Save next byte */ + *p8 = in [3]; + p8++; + len--; + addr++; + + /* Toggle chip select high */ + phy3250_spi_cs_set(0, 1); + } + + /* Stop SSP0 */ + __raw_writel(0, SSP_CR0(sspiobase)); + + /* Restore clock */ + __raw_writel(svclk, CLKPWR_SSP_CLK_CTRL(CLKPWR_IOBASE)); + + if (phyhwdata.fieldvval != PHY_HW_VER_VAL) + { + printk(KERN_ERR "Invalid board descriptor!\n"); + } +#if defined (BOARDDEBUG) + else + { + printk(KERN_INFO "Hardware descriptor info:\n"); + printk(KERN_INFO " DRAM config word: 0x%08x\n", phyhwdata.dramcfg); + printk(KERN_INFO " syscfg word: 0x%08x\n", phyhwdata.syscfg); + printk(KERN_INFO " fieldval word: 0x%08x\n", phyhwdata.fieldvval); + printk(KERN_INFO " MAC address: "); + printk(KERN_INFO "%02x:%02x:%02x:%02x:%02x:%02x\n", + phyhwdata.mac [0], phyhwdata.mac [1], phyhwdata.mac [2], + phyhwdata.mac [3], phyhwdata.mac [4], phyhwdata.mac [5]); + } +#endif +} + +/* + * Board specific functions + */ +void __init phy3250_board_init(void) +{ + u32 tmp; + +#if defined (CONFIG_MMC_ARMMMCI) + /* Enable SD slot power */ + mmc_power_enable(1); +#endif + +#if defined (CONFIG_PHY3250_ENABLE_LED_TICK) + /* Set LED GPIO as an output */ + __raw_writel(OUTP_STATE_GPO(1), GPIO_P2_DIR_SET(GPIO_IOBASE)); +#endif + +#if defined (CONFIG_LPC32XX_MII) + /* Setup network interface for RMII mode */ + tmp = __raw_readl(CLKPWR_MACCLK_CTRL(CLKPWR_IOBASE)); + tmp &= ~CLKPWR_MACCTRL_PINS_MSK; +#if defined (CONFIG_MAC_LPC32XX_MII_SUPPORT) + tmp |= CLKPWR_MACCTRL_USE_MII_PINS; +#else + tmp |= CLKPWR_MACCTRL_USE_RMII_PINS; +#endif + __raw_writel(tmp, CLKPWR_MACCLK_CTRL(CLKPWR_IOBASE)); +#endif + + /* Setup SLC NAND controller */ + __raw_writel(CLKPWR_NANDCLK_SEL_SLC, CLKPWR_NAND_CLK_CTRL(CLKPWR_IOBASE)); + +#if defined (CONFIG_PHY3250_LCD_PANEL) + /* Setup LCD muxing to RGB565 */ + tmp = __raw_readl(CLKPWR_LCDCLK_CTRL(CLKPWR_IOBASE)) & + ~(CLKPWR_LCDCTRL_LCDTYPE_MSK | CLKPWR_LCDCTRL_PSCALE_MSK); + tmp |= CLKPWR_LCDCTRL_LCDTYPE_TFT16; + __raw_writel(tmp, CLKPWR_LCDCLK_CTRL(CLKPWR_IOBASE)); +#endif + + /* Set up I2C levels */ + tmp = __raw_readl(CLKPWR_I2C_CLK_CTRL(CLKPWR_IOBASE)); + tmp |= CLKPWR_I2CCLK_USBI2CHI_DRIVE | CLKPWR_I2CCLK_I2C2HI_DRIVE; + __raw_writel(tmp, CLKPWR_I2C_CLK_CTRL(CLKPWR_IOBASE)); + + /* Enable DMA for I2S1 channel */ + tmp = __raw_readl(CLKPWR_I2S_CLK_CTRL(CLKPWR_IOBASE)); + tmp |= CLKPWR_I2SCTRL_I2S1_USE_DMA; + __raw_writel(tmp, CLKPWR_I2S_CLK_CTRL(CLKPWR_IOBASE)); + + /* Load the board hardware descriptor, as some other board functions + require it's data */ + phy3250_load_hw_desc(); + + /* Call chip specific init */ + lpc32xx_init(); + + /* Disable UART5->USB transparent mode or USB won't work */ + tmp = __raw_readl(UARTCTL_CTRL(io_p2v(UART_CTRL_BASE))); + tmp &= ~UART_U5_ROUTE_TO_USB; + __raw_writel(tmp, UARTCTL_CTRL(io_p2v(UART_CTRL_BASE))); + + /* Test clock needed for UDA1380 - provides a dummy SYSCLK during + UDA1380 init */ // FIXME - is this needed? + __raw_writel((CLKPWR_TESTCLK2_SEL_MOSC | CLKPWR_TESTCLK_TESTCLK2_EN | + CLKPWR_TESTCLK1_SEL_MOSC | CLKPWR_TESTCLK_TESTCLK1_EN), + CLKPWR_TEST_CLK_SEL(CLKPWR_IOBASE)); + +#if defined(CONFIG_RTC_DRV_PCF8563) + /* I2C based RTC device on I2C1 */ + i2c_register_board_info(0, phy3250_i2c_board_info, + ARRAY_SIZE(phy3250_i2c_board_info)); +#endif +} + +MACHINE_START (LPC3XXX, "Phytec 3250 board with the LPC3250 Microcontroller") + /* Maintainer: Kevin Wells, NXP Semiconductors */ + .phys_io = UART5_BASE, + .io_pg_offst = ((io_p2v (UART5_BASE))>>18) & 0xfffc, + .boot_params = 0x80000100, + .map_io = lpc32xx_map_io, + .init_irq = lpc32xx_init_irq, + .timer = &lpc32xx_timer, + .init_machine = phy3250_board_init, +MACHINE_END + diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/clocks-lpc32xx.c linux-2.6.27.8/arch/arm/mach-lpc32xx/clocks-lpc32xx.c --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/clocks-lpc32xx.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/clocks-lpc32xx.c 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,2116 @@ +/* + * linux/arch/arm/mach-lpc32xx/clock.c + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 + */ +/* + * Functions of this driver: + * This driver provides system clocking and control mechanisms for most + * peripheral clocks and partial control over systems clocks. + * The clock organization of the system is as follows: + * RTC clock + * | + * PLL397 Main oscillator + * | | | + * +------------------------------------+ | + * | | + * SYSCLK USB PLL + * | + * Arm PLL (HCLKPLL) + * | + * +-----------------+------------------+ + * | | | + * HCLK (divider) PCLK (divider) SD card clock + * | + * Peripherals (many) + * + * The PLL397 and main oscillator can be individually enabled and + * disabled using clk_enable(), clk_disable(), or clk_rate_set(). + * The clk_rate_get() function will return the actual frequency of + * those oscillators or 0 Hz if they are disabled. + * + * The USB PLL clock can be enabled and disabled using the clk_enable(), + * clk_disable(), clk_set_rate(), and clk_round_rate() functions. The + * clk_rate_get() function will return the actual rate of the USB PLL + * in Hz (or 0 if disabled). + * + * The ARM PLL clock can be enabled and disabled using the clk_enable(), + * clk_disable(), clk_set_rate(), and clk_round_rate() functions. The + * clk_rate_get() function will return the actual rate of the USB PLL + * in Hz (or 0 if disabled). + */ + +#define CLKDEBUG + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +static LIST_HEAD(clocks); + +static struct clk osc_pll397; + +static void clk_upate_children(struct clk *clk); +static void local_update_armpll_rate(void); +static void local_update_usbpll_rate(void); + +/* + * Structure used for setting up and querying the HCLK PLL + */ +typedef struct +{ + /* (0) = analog off, (!0) = on */ + int analog_on; + /* (0) = CCO clock sent to post divider, (!0) = PLL input clock sent + to post div */ + int cco_bypass_b15; + /* (0) = PLL out from post divider, (!0) = PLL out bypasses post + divider */ + int direct_output_b14; + /* (0) = use CCO clock, (!0) = use FCLKOUT */ + int fdbk_div_ctrl_b13; + /* Must be 1, 2, 4, or 8 */ + int pll_p; + /* Must be 1, 2, 3, or 4 */ + int pll_n; + /* Feedback multiplier 1-256 */ + u32 pll_m; +} CLKPWR_HCLK_PLL_SETUP_T; + +/* + * Post divider values for PLLs based on selected register value + */ +static u32 pll_postdivs[4] = {1, 2, 4, 8}; + +#define CLKPWR_IOBASE io_p2v(CLK_PM_BASE) +#define USB_OTG_IOBASE io_p2v(USB_BASE) + +static int local_clk_dummy_set_rate(struct clk *clk, u32 rate) +{ + return 0; +} + +static u32 local_clk_get_st_rate(struct clk *clk) +{ + return clk->rate; +} + +static int local_clk_dummy_enable(struct clk *clk, int enable) +{ + return 0; +} + +/* Primary system clock sources */ +struct clk osc_32KHz = +{ + .owner = NULL, + .name = "osc_32KHz", + .parent = NULL, + .rate = CLOCK_OSC_FREQ, + .flags = CLK_FLAG_FIXED, + .usecount = 0, + .set_rate = &local_clk_dummy_set_rate, + .set_parent = NULL, + .round_rate = NULL, + .get_rate = &local_clk_get_st_rate, + .enable = &local_clk_dummy_enable, + .enable_reg = 0, + .enable_mask = 0, +}; + +static void clk_upate_children(struct clk *clk) +{ + local_update_armpll_rate(); + local_update_usbpll_rate(); +} + +static int local_pll397_set_rate(struct clk *clk, u32 rate) +{ + u32 reg; + + reg = __raw_readl(CLKPWR_PLL397_CTRL(CLKPWR_IOBASE)); + + /* Disable if rate is 0 */ + if (rate == 0) + { + /* 1 = disable for PLL397 */ + reg |= CLKPWR_SYSCTRL_PLL397_DIS; + __raw_writel(reg, CLKPWR_PLL397_CTRL(CLKPWR_IOBASE)); + clk->rate = 0; + } + else + { + /* Enable PLL397 */ + reg &= ~CLKPWR_SYSCTRL_PLL397_DIS; + __raw_writel(reg, CLKPWR_PLL397_CTRL(CLKPWR_IOBASE)); + clk->rate = CLOCK_OSC_FREQ * 397; + + /* Wait for PLL397 lock */ + while ((__raw_readl(CLKPWR_PLL397_CTRL(CLKPWR_IOBASE)) & + CLKPWR_SYSCTRL_PLL397_STS) == 0); + } + + /* Update clocks derived from this clock */ + clk_upate_children(clk); + + return 0; +} + +static int local_pll397_enable(struct clk *clk, int enable) +{ + return (int) local_pll397_set_rate(clk, (u32) enable); +} + + +static int local_oscmain_set_rate(struct clk *clk, u32 rate) +{ + u32 reg; + + reg = __raw_readl(CLKPWR_MAIN_OSC_CTRL(CLKPWR_IOBASE)); + + /* Disable if rate is 0 */ + if (rate == 0) + { + /* 1 = disable for main oscillator */ + reg |= CLKPWR_MOSC_DISABLE; + __raw_writel(reg, CLKPWR_MAIN_OSC_CTRL(CLKPWR_IOBASE)); + clk->rate = 0; + } + else + { + /* Enable main oscillator */ + reg &= ~CLKPWR_MOSC_DISABLE; + __raw_writel(reg, CLKPWR_MAIN_OSC_CTRL(CLKPWR_IOBASE)); + clk->rate = MAIN_OSC_FREQ; + + /* Wait for main oscillator to start */ + while ((__raw_readl(CLKPWR_MAIN_OSC_CTRL(CLKPWR_IOBASE)) & + CLKPWR_MOSC_DISABLE) != 0); + } + + /* Update clocks derived from this clock */ + clk_upate_children(clk); + + return 0; +} + +static int local_oscmain_enable(struct clk *clk, int enable) +{ + return (int) local_oscmain_set_rate(clk, (u32) enable); +} + +static int local_sysclk_set_rate(struct clk *clk, u32 rate) +{ + u32 reg, ret = 0; + + reg = __raw_readl(CLKPWR_SYSCLK_CTRL(CLKPWR_IOBASE)); + + if (rate == 0) + { + /* 0 = Switch to main oscillator */ + reg &= ~CLKPWR_SYSCTRL_USEPLL397; + __raw_writel(reg, CLKPWR_SYSCLK_CTRL(CLKPWR_IOBASE)); + clk->parent = &osc_main; + } + else + { + /* 1 = Switch to PLL397 opscillator */ + reg |= CLKPWR_SYSCTRL_USEPLL397; + __raw_writel(reg, CLKPWR_SYSCLK_CTRL(CLKPWR_IOBASE)); + clk->parent = &osc_pll397; + } + + clk->rate = clk->parent->rate; + + /* Update clocks derived from this clock */ + clk_upate_children(clk); + + return ret; +} + +static int local_sysclk_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, ret = 0; + + reg = __raw_readl(CLKPWR_SYSCLK_CTRL(CLKPWR_IOBASE)); + + if (parent == &osc_main) + { + local_sysclk_set_rate(parent, 0); + } + else if (parent == &osc_pll397) + { + local_sysclk_set_rate(parent, 1); + } + else + { + ret = -EINVAL; + } + + return ret; +} + +static struct clk osc_pll397 = +{ + .owner = NULL, + .name = "osc_pll397", + .parent = &osc_32KHz, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &local_pll397_set_rate, + .set_parent = NULL, + .round_rate = NULL, + .get_rate = NULL, + .enable = &local_pll397_enable, + .enable_reg = 0, + .enable_mask = 0, +}; +struct clk osc_main = +{ + .owner = NULL, + .name = "osc_main", + .parent = NULL, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &local_oscmain_set_rate, + .set_parent = NULL, + .round_rate = NULL, + .get_rate = NULL, + .enable = &local_oscmain_enable, + .enable_reg = 0, + .enable_mask = 0, +}; +static struct clk clk_sys = +{ + .owner = NULL, + .name = "sys_ck", + .parent = &osc_main, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &local_sysclk_set_rate, /* 0 = main osc, 1 = PLL397 */ + .set_parent = local_sysclk_set_parent, /* Can set osc_main or osc_pll397 as parent */ + .round_rate = NULL, + .get_rate = NULL, + .enable = &local_clk_dummy_enable, + .enable_reg = 0, + .enable_mask = 0, +}; + +/* + * Computes PLL rate from PLL register and input clock + */ +static u32 local_clk_check_pll_setup(u32 ifreq, CLKPWR_HCLK_PLL_SETUP_T *pllsetup) +{ + u32 i64freq, p, m, n, fcco, fref, cfreq; + int mode; + + /* PLL requirements */ + /* ifreq must be >= 1MHz and <= 20MHz */ + /* FCCO must be >= 156MHz and <= 320MHz */ + /* FREF must be >= 1MHz and <= 27MHz. */ + /* Assume the passed input data is not valid */ + + /* Work with 64-bit values to prevent overflow */ + i64freq = ifreq; + m = pllsetup->pll_m; + n = pllsetup->pll_n; + p = pllsetup->pll_p; + + /* Get components of the PLL register */ + mode = (pllsetup->cco_bypass_b15 << 2) | + (pllsetup->direct_output_b14 << 1) | + pllsetup->fdbk_div_ctrl_b13; + + switch (mode) + { + case 0x0: /* Non-integer mode */ + cfreq = (m * i64freq) / (2 * p * n); + fcco = (m * i64freq) / n; + fref = i64freq / n; + break; + + case 0x1: /* integer mode */ + cfreq = (m * i64freq) / n; + fcco = (m * i64freq) / (n * 2 * p); + fref = i64freq / n; + break; + + case 0x2: + case 0x3: /* Direct mode */ + cfreq = (m * i64freq) / n; + fcco = cfreq; + fref = i64freq / n; + break; + + case 0x4: + case 0x5: /* Bypass mode */ + cfreq = i64freq / (2 * p); + fcco = 156000000; + fref = 1000000; + break; + + case 0x6: + case 0x7: /* Direct bypass mode */ + default: + cfreq = i64freq; + fcco = 156000000; + fref = 1000000; + break; + } + + if ((fcco < 156000000) || (fcco > 320000000)) + { + /* not a valid range */ + cfreq = 0; + } + + if ((fref < 1000000) || (fref > 27000000)) + { + /* not a valid range */ + cfreq = 0; + } + + return (u32) cfreq; +} + +/* + * Convert a PLL register value to a PLL output frequency + */ +u32 local_clk_get_pllrate_from_reg(u32 inputclk, u32 regval) +{ + CLKPWR_HCLK_PLL_SETUP_T pllcfg; + + /* Get components of the PLL register */ + pllcfg.cco_bypass_b15 = 0; + pllcfg.direct_output_b14 = 0; + pllcfg.fdbk_div_ctrl_b13 = 0; + if ((regval & CLKPWR_HCLKPLL_CCO_BYPASS) != 0) + { + pllcfg.cco_bypass_b15 = 1; + } + if ((regval & CLKPWR_HCLKPLL_POSTDIV_BYPASS) != 0) + { + pllcfg.direct_output_b14 = 1; + } + if ((regval & CLKPWR_HCLKPLL_FDBK_SEL_FCLK) != 0) + { + pllcfg.fdbk_div_ctrl_b13 = 1; + } + pllcfg.pll_m = 1 + ((regval >> 1) & 0xFF); + pllcfg.pll_n = 1 + ((regval >> 9) & 0x3); + pllcfg.pll_p = pll_postdivs[((regval >> 11) & 0x3)]; + + return local_clk_check_pll_setup(inputclk, &pllcfg); +} + +/* + * Update the ARM core PLL frequency rate variable from the actual PLL setting + */ +static void local_update_armpll_rate(void) +{ + u32 clkin, pllreg; + + /* Get PLL input clock rate */ + clkin = clk_armpll.parent->rate; + + /* Get ARM HCLKPLL register */ + pllreg = __raw_readl(CLKPWR_HCLKPLL_CTRL(CLKPWR_IOBASE)) & 0x1FFFF; + + clk_armpll.rate = local_clk_get_pllrate_from_reg(clkin, pllreg); +} + +static int clkpwr_abs(int v1, int v2) +{ + if (v1 > v2) + { + return v1 - v2; + } + + return v2 - v1; +} + +/* + * Find a PLL configuration for the selected input frequency + */ +static u32 local_clk_find_pll_cfg(u32 pllin_freq, + u32 target_freq, + CLKPWR_HCLK_PLL_SETUP_T *pllsetup) +{ + u32 ifreq, freqtol, m, n, p, fclkout = 0; + u32 flag = 0, freqret = 0; + + /* Determine frequency tolerance limits */ + freqtol = target_freq / 250; + + /* Get PLL clock */ + ifreq = pllin_freq; + + /* Is direct bypass mode possible? */ + if (clkpwr_abs(pllin_freq, target_freq) <= freqtol) + { + flag = 1; + pllsetup->analog_on = 0; + pllsetup->cco_bypass_b15 = 1; /* Bypass CCO */ + pllsetup->direct_output_b14 = 1; /* Bypass post divider */ + pllsetup->fdbk_div_ctrl_b13 = 1; + pllsetup->pll_p = pll_postdivs[0]; /* Doesn't matter */ + pllsetup->pll_n = 1; /* Doesn't matter */ + pllsetup->pll_m = 1; /* Doesn't matter */ + fclkout = local_clk_check_pll_setup(ifreq, pllsetup); + } + else if (target_freq <= ifreq) /* Is bypass mode possible? */ + { + pllsetup->analog_on = 0; + pllsetup->cco_bypass_b15 = 1; /* Bypass CCO */ + pllsetup->direct_output_b14 = 0; + pllsetup->fdbk_div_ctrl_b13 = 1; + pllsetup->pll_n = 1; /* Doesn't matter */ + pllsetup->pll_m = 1; /* Doesn't matter */ + for (p = 0; ((p <= 3) && (flag == 0)); p++) + { + pllsetup->pll_p = pll_postdivs[p]; + fclkout = local_clk_check_pll_setup(ifreq, pllsetup); + if (clkpwr_abs(target_freq, fclkout) <= freqtol) + { + /* Found a matching frequency */ + flag = 1; + } + } + } + + /* Is direct mode possible? */ + if (flag == 0) + { + pllsetup->analog_on = 1; + pllsetup->cco_bypass_b15 = 0; /* Bypass CCO */ + pllsetup->direct_output_b14 = 1; + pllsetup->fdbk_div_ctrl_b13 = 0; + pllsetup->pll_p = pll_postdivs[0]; + for (m = 1; ((m <= 256) && (flag == 0)); m++) + { + for (n = 1; ((n <= 4) && (flag == 0)); n++) + { + /* Compute output frequency for this value */ + pllsetup->pll_n = n; + pllsetup->pll_m = m; + fclkout = local_clk_check_pll_setup(ifreq, pllsetup); + if (clkpwr_abs(target_freq, fclkout) <= freqtol) + { + flag = 1; + } + } + } + } + + /* Is integer mode possible? */ + if (flag == 0) + { + /* Bypass and direct modes won't work with this frequency, so + integer mode may need to be used */ + pllsetup->analog_on = 1; + pllsetup->cco_bypass_b15 = 0; + pllsetup->direct_output_b14 = 0; + pllsetup->fdbk_div_ctrl_b13 = 1; + for (m = 1; ((m <= 256) && (flag == 0)); m++) + { + for (n = 1; ((n <= 4) && (flag == 0)); n++) + { + for (p = 0; ((p < 4) && (flag == 0)); p++) + { + /* Compute output frequency for this value */ + pllsetup->pll_p = pll_postdivs[p]; + pllsetup->pll_n = n; + pllsetup->pll_m = m; + fclkout = local_clk_check_pll_setup(ifreq, pllsetup); + if (clkpwr_abs(target_freq, fclkout) <= freqtol) + { + flag = 1; + } + } + } + } + } + + if (flag == 0) + { + /* Try non-integer mode */ + pllsetup->analog_on = 1; + pllsetup->cco_bypass_b15 = 0; + pllsetup->direct_output_b14 = 0; + pllsetup->fdbk_div_ctrl_b13 = 0; + for (m = 1; ((m <= 256) && (flag == 0)); m++) + { + for (n = 1; ((n <= 4) && (flag == 0)); n++) + { + for (p = 0; ((p < 4) && (flag == 0)); p++) + { + /* Compute output frequency for this value */ + pllsetup->pll_p = pll_postdivs[p]; + pllsetup->pll_n = n; + pllsetup->pll_m = m; + fclkout = local_clk_check_pll_setup(ifreq, pllsetup); + if (clkpwr_abs(target_freq, fclkout) <= freqtol) + { + flag = 1; + } + } + } + } + } + + if (flag == 1) + { + freqret = fclkout; + } + + return freqret; +} + +/* + * Setup the HCLK PLL with a PLL structure + */ +static u32 local_clk_hclkpll_setup(CLKPWR_HCLK_PLL_SETUP_T *pHCLKPllSetup) +{ + u32 tv, tmp = 0; + + if (pHCLKPllSetup->analog_on != 0) + { + tmp |= CLKPWR_HCLKPLL_POWER_UP; + } + if (pHCLKPllSetup->cco_bypass_b15 != 0) + { + tmp |= CLKPWR_HCLKPLL_CCO_BYPASS; + } + if (pHCLKPllSetup->direct_output_b14 != 0) + { + tmp |= CLKPWR_HCLKPLL_POSTDIV_BYPASS; + } + if (pHCLKPllSetup->fdbk_div_ctrl_b13 != 0) + { + tmp |= CLKPWR_HCLKPLL_FDBK_SEL_FCLK; + } + + switch (pHCLKPllSetup->pll_p) + { + case 1: + tv = 0; + break; + + case 2: + tv = 1; + break; + + case 4: + tv = 2; + break; + + case 8: + tv = 3; + break; + + default: + return 0; + } + tmp |= CLKPWR_HCLKPLL_POSTDIV_2POW(tv); + tmp |= CLKPWR_HCLKPLL_PREDIV_PLUS1(pHCLKPllSetup->pll_n - 1); + tmp |= CLKPWR_HCLKPLL_PLLM(pHCLKPllSetup->pll_m - 1); + + __raw_writel(tmp, CLKPWR_HCLKPLL_CTRL(CLKPWR_IOBASE)); + + return local_clk_check_pll_setup(clk_armpll.parent->rate, pHCLKPllSetup); +} + +static int local_armpll_set_rate(struct clk *clk, u32 rate) +{ + u32 clkin; + CLKPWR_HCLK_PLL_SETUP_T pllsetup; + + if ((rate < 33000000) || (rate > 266000000)) + { + return -EINVAL; + } + + /* Get input frequency to PLL */ + clkin = clk->parent->rate; + + /* Try to find a good rate setup */ + if (local_clk_find_pll_cfg(clkin, rate, &pllsetup) == 0) + { + /* Cannot setup the frequency */ + return -EINVAL; + } + + /* Setup PLL */ + local_clk_hclkpll_setup(&pllsetup); + clk->rate = local_clk_check_pll_setup(clkin, &pllsetup); + + return 0; +} + +static int local_armpll_enable(struct clk *clk, int enable) +{ + u32 reg; + + /* Read PLL reg */ + reg = __raw_readl(CLKPWR_HCLKPLL_CTRL(CLKPWR_IOBASE)); + + if (enable == 0) + { + /* Disable PLL - not recommended unless you really know + what your are doing (must be in direct-run mode!) */ + reg &= ~CLKPWR_HCLKPLL_POWER_UP; + __raw_writel(reg, CLKPWR_HCLKPLL_CTRL(CLKPWR_IOBASE)); + clk->rate = 0; + } + else + { + reg |= CLKPWR_HCLKPLL_POWER_UP; + __raw_writel(reg, CLKPWR_HCLKPLL_CTRL(CLKPWR_IOBASE)); + + /* Wait for PLL lock */ + while ((__raw_readl(CLKPWR_HCLKPLL_CTRL(CLKPWR_IOBASE)) & + CLKPWR_HCLKPLL_PLL_STS) == 0); + + local_update_armpll_rate(); + } + + return 0; +} + +/* + * Update the USB PLL frequency rate variable from the actual PLL setting + */ +static void local_update_usbpll_rate(void) +{ + u32 clkin, pllreg; + + /* Get PLL input clock rate */ + clkin = clk_armpll.parent->rate; + + /* Get USBPLL register */ + pllreg = __raw_readl(CLKPWR_USB_CTRL(CLKPWR_IOBASE)) & 0x1FFFF; + + if ((pllreg & CLKPWR_USBCTRL_PLL_PWRUP) == 0) + { + clk_usbpll.rate = 0; + } + else + { + clk_usbpll.rate = local_clk_get_pllrate_from_reg(clkin, pllreg); + } +} + +/* + * Setup the USB PLL with a PLL structure + */ +static u32 local_clk_usbpll_setup(CLKPWR_HCLK_PLL_SETUP_T *pHCLKPllSetup) +{ + u32 tv, reg, tmp = 0; + + if (pHCLKPllSetup->analog_on != 0) + { + tmp |= CLKPWR_HCLKPLL_POWER_UP; + } + if (pHCLKPllSetup->cco_bypass_b15 != 0) + { + tmp |= CLKPWR_HCLKPLL_CCO_BYPASS; + } + if (pHCLKPllSetup->direct_output_b14 != 0) + { + tmp |= CLKPWR_HCLKPLL_POSTDIV_BYPASS; + } + if (pHCLKPllSetup->fdbk_div_ctrl_b13 != 0) + { + tmp |= CLKPWR_HCLKPLL_FDBK_SEL_FCLK; + } + + switch (pHCLKPllSetup->pll_p) + { + case 1: + tv = 0; + break; + + case 2: + tv = 1; + break; + + case 4: + tv = 2; + break; + + case 8: + tv = 3; + break; + + default: + return 0; + } + tmp |= CLKPWR_HCLKPLL_POSTDIV_2POW(tv); + tmp |= CLKPWR_HCLKPLL_PREDIV_PLUS1(pHCLKPllSetup->pll_n - 1); + tmp |= CLKPWR_HCLKPLL_PLLM(pHCLKPllSetup->pll_m - 1); + + reg = __raw_readl(CLKPWR_USB_CTRL(CLKPWR_IOBASE)) & ~0x1FFFF; + reg |= tmp; + __raw_writel(reg, CLKPWR_USB_CTRL(CLKPWR_IOBASE)); + + return local_clk_check_pll_setup(clk_usbpll.parent->rate, pHCLKPllSetup); +} + +static int local_usbpll_enable(struct clk *clk, int enable) +{ + u32 reg; + int ret = -ENODEV, qj = (jiffies / 4); + + reg = __raw_readl(CLKPWR_USB_CTRL(CLKPWR_IOBASE)); + + /* Only disable is supported */ + if (enable == 0) + { + /* Stop PLL clocking */ + reg &= ~(CLKPWR_USBCTRL_CLK_EN1 | CLKPWR_USBCTRL_CLK_EN2); + __raw_writel(reg, CLKPWR_USB_CTRL(CLKPWR_IOBASE)); + } + else if (reg & CLKPWR_USBCTRL_PLL_PWRUP) + { + /* Start PLL clock input */ + reg |= CLKPWR_USBCTRL_CLK_EN1; + __raw_writel(reg, CLKPWR_USB_CTRL(CLKPWR_IOBASE)); + + /* Wait for PLL lock */ + while (qj < jiffies) + { + reg = __raw_readl(CLKPWR_USB_CTRL(CLKPWR_IOBASE)); + if (reg & CLKPWR_USBCTRL_PLL_STS) + { + ret = 0; + } + } + + if (ret == 0) + { + /* Allow PLL output clock */ + reg |= CLKPWR_USBCTRL_CLK_EN2; + __raw_writel(reg, CLKPWR_USB_CTRL(CLKPWR_IOBASE)); + } + } + + return ret; +} + +static int local_usbpll_set_rate(struct clk *clk, u32 rate) +{ + u32 clkin, reg, usbdiv; + CLKPWR_HCLK_PLL_SETUP_T pllsetup; + + /* Unlike other clocks, this clock has a KHz input rate, so bump + it up to work with the PLL function */ + rate = rate * 1000; + + /* Stop clocks */ + local_usbpll_enable(clk, 0); + + if (rate == 0) + { + return 0; + } + + /* Get input frequency to PLL */ + clkin = clk->parent->rate; + usbdiv = __raw_readl(CLKPWR_USBCLK_PDIV(CLKPWR_IOBASE)) + 1; + clkin = clkin / usbdiv; + + /* Try to find a good rate setup */ + if (local_clk_find_pll_cfg(clkin, rate, &pllsetup) == 0) + { + /* Cannot setup the frequency */ + return -EINVAL; + } + + /* Start PLL clock input */ + reg = __raw_readl(CLKPWR_USB_CTRL(CLKPWR_IOBASE)); + reg |= CLKPWR_USBCTRL_CLK_EN1; + __raw_writel(reg, CLKPWR_USB_CTRL(CLKPWR_IOBASE)); + + /* Setup PLL */ + pllsetup.analog_on = 1; + local_clk_usbpll_setup(&pllsetup); + + clk->rate = local_clk_check_pll_setup(clkin, &pllsetup); + + /* Enable PLL output */ + reg = __raw_readl(CLKPWR_USB_CTRL(CLKPWR_IOBASE)); + reg |= CLKPWR_USBCTRL_CLK_EN2; + __raw_writel(reg, CLKPWR_USB_CTRL(CLKPWR_IOBASE)); + + return 0; +} + +/* Derived system clock sources */ +struct clk clk_armpll = +{ + .owner = NULL, + .name = "arm_pll_ck", + .parent = &clk_sys, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &local_armpll_set_rate, + .set_parent = NULL, + .round_rate = NULL, + .get_rate = &local_clk_get_st_rate, + .enable = &local_armpll_enable, + .enable_reg = 0, + .enable_mask = 0, +}; +struct clk clk_usbpll = +{ + .owner = NULL, + .name = "ck_pll5", /* USB PLL clock */ + .parent = &osc_main, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &local_usbpll_set_rate, + .set_parent = NULL, + .round_rate = NULL, + .get_rate = &local_clk_get_st_rate, + .enable = &local_usbpll_enable, + .enable_reg = 0, + .enable_mask = 0, +}; + +static u32 clk_get_hclk_div(void) +{ + static const u32 hclkdivs[4] = {1, 2, 4, 4}; + return hclkdivs[CLKPWR_HCLKDIV_DIV_2POW( + __raw_readl(CLKPWR_HCLK_DIV(CLKPWR_IOBASE)))]; +} + +/* + * Set new HCLK bus divider value + */ +static int clk_set_hclk_div(struct clk *clk, u32 div) +{ + u32 hclkdiv = __raw_readl(CLKPWR_HCLK_DIV(CLKPWR_IOBASE)); + + hclkdiv &= ~CLKPWR_HCLKDIV_DIV_2POW(0x3); + switch (div) + { + case 1: + case 2: + hclkdiv |= CLKPWR_HCLKDIV_DIV_2POW(div - 1); + break; + + case 4: + default: + hclkdiv |= CLKPWR_HCLKDIV_DIV_2POW(2); + break; + } + __raw_writel(hclkdiv, CLKPWR_HCLK_DIV(CLKPWR_IOBASE)); + + return 0; +} + +static u32 local_hclk_get_rate(struct clk *clk) +{ + return clk->parent->rate / clk_get_hclk_div(); +} + +u32 clk_get_pclk_div(void) +{ + return (1 + ((__raw_readl(CLKPWR_HCLK_DIV(CLKPWR_IOBASE)) >> 2) & 0x1F)); +} + +/* + * Set new PCLK bus divider value + */ +static int clk_set_pclk_div(struct clk *clk, u32 div) +{ + u32 hclkdiv = __raw_readl(CLKPWR_HCLK_DIV(CLKPWR_IOBASE)); + + hclkdiv &= ~CLKPWR_HCLKDIV_PCLK_DIV(0x1F); + if (div > 32) + { + /* Limit PCLK divider */ + div = 32; + } + + hclkdiv |= CLKPWR_HCLKDIV_PCLK_DIV(div - 1); + __raw_writel(hclkdiv, CLKPWR_HCLK_DIV(CLKPWR_IOBASE)); + + return 0; +} + +static u32 local_pclk_get_rate(struct clk *clk) +{ + return clk->parent->rate / clk_get_pclk_div(); +} + +/* Bus clocks */ +struct clk clk_hclk = +{ + .owner = NULL, + .name = "hclk_ck", + .parent = &clk_armpll, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &clk_set_hclk_div, + .set_parent = NULL, + .round_rate = NULL, + .get_rate = &local_hclk_get_rate, + .enable = &local_clk_dummy_enable, + .enable_reg = 0, + .enable_mask = 0, +}; +struct clk clk_pclk = +{ + .owner = NULL, + .name = "pclk_ck", + .parent = &clk_armpll, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &clk_set_pclk_div, + .set_parent = NULL, + .round_rate = NULL, + .get_rate = &local_pclk_get_rate, + .enable = &local_clk_dummy_enable, + .enable_reg = 0, +}; + +static int local_onoff_set_rate(struct clk *clk, u32 rate) +{ + u32 tmp; + + tmp = __raw_readl(clk->enable_reg); + + /* Disable clock if rate is 0 */ + if (rate == 0) + { + tmp &= ~clk->enable_mask; + } + else + { + tmp |= clk->enable_mask; + } + + __raw_writel(tmp, clk->enable_reg); + + return 0; +} + +static u32 local_get_periph_rate(struct clk *clk) +{ + u32 tmp; + + tmp = __raw_readl(clk->enable_reg) & clk->enable_mask; + + if (!tmp) + { + /* Clock is disabled */ + return 0; + } + + if (clk->parent != NULL) + { + /* If the parent clock has a get_rate function, call it */ + if (clk->parent->get_rate != NULL) + { + return clk->parent->get_rate(clk->parent); + } + + return clk->parent->rate; + } + + return 1; +} + +static int local_onoff_enable(struct clk *clk, int enable) +{ + return local_onoff_set_rate(clk, enable); +} + +static u32 local_onoff_round_rate(struct clk *clk, u32 rate) +{ + return (rate ? 1 : 0); +} + +/* Peripheral clock sources */ +static struct clk clk_timer0 = +{ + .owner = NULL, + .name = "timer0_ck", + .parent = &clk_pclk, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &local_onoff_set_rate, + .set_parent = NULL, + .round_rate = &local_onoff_round_rate, + .get_rate = &local_get_periph_rate, + .enable = &local_onoff_enable, + .enable_reg = CLKPWR_TIMERS_PWMS_CLK_CTRL_1(CLKPWR_IOBASE), + .enable_mask = CLKPWR_TMRPWMCLK_TIMER0_EN, +}; +static struct clk clk_timer1 = +{ + .owner = NULL, + .name = "timer1_ck", + .parent = &clk_pclk, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &local_onoff_set_rate, + .set_parent = NULL, + .round_rate = &local_onoff_round_rate, + .get_rate = &local_get_periph_rate, + .enable = &local_onoff_enable, + .enable_reg = CLKPWR_TIMERS_PWMS_CLK_CTRL_1(CLKPWR_IOBASE), + .enable_mask = CLKPWR_TMRPWMCLK_TIMER1_EN, +}; +static struct clk clk_timer2 = +{ + .owner = NULL, + .name = "timer2_ck", + .parent = &clk_pclk, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &local_onoff_set_rate, + .set_parent = NULL, + .round_rate = &local_onoff_round_rate, + .get_rate = &local_get_periph_rate, + .enable = &local_onoff_enable, + .enable_reg = CLKPWR_TIMERS_PWMS_CLK_CTRL_1(CLKPWR_IOBASE), + .enable_mask = CLKPWR_TMRPWMCLK_TIMER2_EN, +}; +static struct clk clk_timer3 = +{ + .owner = NULL, + .name = "timer3_ck", + .parent = &clk_pclk, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &local_onoff_set_rate, + .set_parent = NULL, + .round_rate = &local_onoff_round_rate, + .get_rate = &local_get_periph_rate, + .enable = &local_onoff_enable, + .enable_reg = CLKPWR_TIMERS_PWMS_CLK_CTRL_1(CLKPWR_IOBASE), + .enable_mask = CLKPWR_TMRPWMCLK_TIMER3_EN, +}; +#if defined (CONFIG_LPC32XX_WATCHDOG) +static struct clk clk_wdt = +{ + .owner = NULL, + .name = "wdt_ck", + .parent = &clk_pclk, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &local_onoff_set_rate, + .set_parent = NULL, + .round_rate = &local_onoff_round_rate, + .get_rate = &local_get_periph_rate, + .enable = &local_onoff_enable, + .enable_reg = CLKPWR_TIMER_CLK_CTRL(CLKPWR_IOBASE), + .enable_mask = CLKPWR_PWMCLK_WDOG_EN, +}; +#endif +static struct clk clk_vfp9 = +{ + .owner = NULL, + .name = "vfp9_ck", + .parent = &clk_pclk, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &local_onoff_set_rate, + .set_parent = NULL, + .round_rate = &local_onoff_round_rate, + .get_rate = &local_get_periph_rate, + .enable = &local_onoff_enable, + .enable_reg = CLKPWR_DEBUG_CTRL(CLKPWR_IOBASE), + .enable_mask = CLKPWR_VFP_CLOCK_ENABLE_BIT, +}; +static struct clk clk_dma = +{ + .owner = NULL, + .name = "clk_dmac", + .parent = &clk_hclk, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &local_onoff_set_rate, + .set_parent = NULL, + .round_rate = &local_onoff_round_rate, + .get_rate = &local_get_periph_rate, + .enable = &local_onoff_enable, + .enable_reg = CLKPWR_DMA_CLK_CTRL(CLKPWR_IOBASE), + .enable_mask = CLKPWR_DMACLKCTRL_CLK_EN, +}; + +#if defined (CONFIG_MACH_LPC32XX_UART3_ENABLE) +static struct clk clk_uart3 = +{ + .owner = NULL, + .name = "uart3_ck", + .parent = &clk_pclk, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &local_onoff_set_rate, + .set_parent = NULL, + .round_rate = &local_onoff_round_rate, + .get_rate = &local_get_periph_rate, + .enable = &local_onoff_enable, + .enable_reg = CLKPWR_UART_CLK_CTRL(CLKPWR_IOBASE), + .enable_mask = CLKPWR_UARTCLKCTRL_UART3_EN, +}; +#endif +#if defined (CONFIG_MACH_LPC32XX_UART4_ENABLE) +static struct clk clk_uart4 = +{ + .owner = NULL, + .name = "uart4_ck", + .parent = &clk_pclk, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &local_onoff_set_rate, + .set_parent = NULL, + .round_rate = &local_onoff_round_rate, + .get_rate = &local_get_periph_rate, + .enable = &local_onoff_enable, + .enable_reg = CLKPWR_UART_CLK_CTRL(CLKPWR_IOBASE), + .enable_mask = CLKPWR_UARTCLKCTRL_UART4_EN, +}; +#endif +#if defined (CONFIG_MACH_LPC32XX_UART5_ENABLE) +static struct clk clk_uart5 = +{ + .owner = NULL, + .name = "uart5_ck", + .parent = &clk_pclk, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &local_onoff_set_rate, + .set_parent = NULL, + .round_rate = &local_onoff_round_rate, + .get_rate = &local_get_periph_rate, + .enable = &local_onoff_enable, + .enable_reg = CLKPWR_UART_CLK_CTRL(CLKPWR_IOBASE), + .enable_mask = CLKPWR_UARTCLKCTRL_UART5_EN, +}; +#endif +#if defined (CONFIG_MACH_LPC32XX_UART6_ENABLE) +static struct clk clk_uart6 = +{ + .owner = NULL, + .name = "uart6_ck", + .parent = &clk_pclk, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &local_onoff_set_rate, + .set_parent = NULL, + .round_rate = &local_onoff_round_rate, + .get_rate = &local_get_periph_rate, + .enable = &local_onoff_enable, + .enable_reg = CLKPWR_UART_CLK_CTRL(CLKPWR_IOBASE), + .enable_mask = CLKPWR_UARTCLKCTRL_UART6_EN, +}; +#endif +#if defined (CONFIG_MACH_LPC32XX_I2C0_ENABLE) +struct clk clk_i2c0 = +{ + .owner = NULL, + .name = "i2c0_ck", + .parent = &clk_hclk, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &local_onoff_set_rate, + .set_parent = NULL, + .round_rate = &local_onoff_round_rate, + .get_rate = &local_get_periph_rate, + .enable = &local_onoff_enable, + .enable_reg = CLKPWR_I2C_CLK_CTRL(CLKPWR_IOBASE), + .enable_mask = CLKPWR_I2CCLK_I2C1CLK_EN, +}; +#endif +#if defined (CONFIG_MACH_LPC32XX_I2C1_ENABLE) +struct clk clk_i2c1 = +{ + .owner = NULL, + .name = "i2c1_ck", + .parent = &clk_hclk, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &local_onoff_set_rate, + .set_parent = NULL, + .round_rate = &local_onoff_round_rate, + .get_rate = &local_get_periph_rate, + .enable = &local_onoff_enable, + .enable_reg = CLKPWR_I2C_CLK_CTRL(CLKPWR_IOBASE), + .enable_mask = CLKPWR_I2CCLK_I2C2CLK_EN, +}; +#endif +#if defined (CONFIG_MACH_LPC32XX_USBOTG_I2C_ENABLE) +struct clk clk_i2c2 = +{ + .owner = NULL, + .name = "i2c2_ck", + .parent = &clk_pclk, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &local_onoff_set_rate, + .set_parent = NULL, + .round_rate = &local_onoff_round_rate, + .get_rate = &local_get_periph_rate, + .enable = &local_onoff_enable, + .enable_reg = USB_OTG_IOBASE + 0xFF4, + .enable_mask = 0x4, +}; +#endif +#if defined(CONFIG_SPI_LPC32XX) +#if defined(CONFIG_MACH_LPC32XX_SSP0_ENABLE) +struct clk clk_ssp0 = +{ + .owner = NULL, + .name = "spi0_ck", + .parent = &clk_hclk, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &local_onoff_set_rate, + .set_parent = NULL, + .round_rate = &local_onoff_round_rate, + .get_rate = &local_get_periph_rate, + .enable = &local_onoff_enable, + .enable_reg = CLKPWR_SSP_CLK_CTRL(CLKPWR_IOBASE), + .enable_mask = CLKPWR_SSPCTRL_SSPCLK0_EN, +}; +#endif +#if defined(CONFIG_MACH_LPC32XX_SSP1_ENABLE) +struct clk clk_ssp1 = +{ + .owner = NULL, + .name = "spi1_ck", + .parent = &clk_hclk, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &local_onoff_set_rate, + .set_parent = NULL, + .round_rate = &local_onoff_round_rate, + .get_rate = &local_get_periph_rate, + .enable = &local_onoff_enable, + .enable_reg = CLKPWR_SSP_CLK_CTRL(CLKPWR_IOBASE), + .enable_mask = CLKPWR_SSPCTRL_SSPCLK1_EN, +}; +#endif +#endif +#if defined(CONFIG_KEYBOARD_LPC32XX) +struct clk clk_kscan = +{ + .owner = NULL, + .name = "key_ck", + .parent = &osc_32KHz, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &local_onoff_set_rate, + .set_parent = NULL, + .round_rate = &local_onoff_round_rate, + .get_rate = &local_get_periph_rate, + .enable = &local_onoff_enable, + .enable_reg = CLKPWR_KEY_CLK_CTRL(CLKPWR_IOBASE), + .enable_mask = CLKPWR_KEYCLKCTRL_CLK_EN, +}; +#endif +#if defined(CONFIG_MTD_NAND_SLC_LPC32XX) +struct clk clk_nand = +{ + .owner = NULL, + .name = "nand_ck", + .parent = &clk_hclk, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &local_onoff_set_rate, + .set_parent = NULL, + .round_rate = &local_onoff_round_rate, + .get_rate = &local_get_periph_rate, + .enable = &local_onoff_enable, + .enable_reg = CLKPWR_NAND_CLK_CTRL(CLKPWR_IOBASE), + .enable_mask = CLKPWR_NANDCLK_SLCCLK_EN, +}; +#endif +#if defined(CONFIG_SND_LPC3XXX_SOC_I2S) +struct clk clk_i2s0 = +{ + .owner = NULL, + .name = "i2s0_ck", + .parent = &clk_hclk, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &local_onoff_set_rate, + .set_parent = NULL, + .round_rate = &local_onoff_round_rate, + .get_rate = &local_get_periph_rate, + .enable = &local_onoff_enable, + .enable_reg = CLKPWR_I2S_CLK_CTRL(CLKPWR_IOBASE), + .enable_mask = CLKPWR_I2SCTRL_I2SCLK0_EN, +}; +struct clk clk_i2s1 = +{ + .owner = NULL, + .name = "i2s1_ck", + .parent = &clk_hclk, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &local_onoff_set_rate, + .set_parent = NULL, + .round_rate = &local_onoff_round_rate, + .get_rate = &local_get_periph_rate, + .enable = &local_onoff_enable, + .enable_reg = CLKPWR_I2S_CLK_CTRL(CLKPWR_IOBASE), + .enable_mask = CLKPWR_I2SCTRL_I2SCLK1_EN, +}; +#endif +#if defined (CONFIG_TOUCHSCREEN_LPC32XX) +static int tsc_onoff_enable(struct clk *clk, int enable) +{ + u32 tmp; + + /* Make sure 32KHz clock is the selected clock */ + tmp = __raw_readl(CLKPWR_ADC_CLK_CTRL_1(CLKPWR_IOBASE)); + tmp &= ~CLKPWR_ADCCTRL1_PCLK_SEL; + __raw_writel(tmp, CLKPWR_ADC_CLK_CTRL_1(CLKPWR_IOBASE)); + + if (enable == 0) + { + __raw_writel(0, clk->enable_reg); + } + else + { + __raw_writel(clk->enable_mask, clk->enable_reg); + } + + return 0; +} +static int tsc_set_rate(struct clk *clk, u32 rate) +{ + return tsc_onoff_enable(clk, rate); +} +struct clk clk_tsc = +{ + .owner = NULL, + .name = "tsc_ck", + .parent = &osc_32KHz, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &tsc_set_rate, + .set_parent = NULL, + .round_rate = &local_onoff_round_rate, + .get_rate = &local_get_periph_rate, + .enable = &tsc_onoff_enable, + .enable_reg = CLKPWR_ADC_CLK_CTRL(CLKPWR_IOBASE), + .enable_mask = CLKPWR_ADC32CLKCTRL_CLK_EN, +}; +#endif +#if defined (CONFIG_MMC_ARMMMCI) +static int mmc_onoff_enable(struct clk *clk, int enable) +{ + u32 tmp; + + tmp = __raw_readl(CLKPWR_MS_CTRL(CLKPWR_IOBASE)) & + ~CLKPWR_MSCARD_SDCARD_EN; + + /* If rate is 0, disable clock */ + if (enable != 0) + { + tmp |= CLKPWR_MSCARD_SDCARD_EN | CLKPWR_MSCARD_SDCARD_DIV(1); + } + + __raw_writel(tmp, CLKPWR_MS_CTRL(CLKPWR_IOBASE)); + + return 0; +} +static u32 mmc_get_rate(struct clk *clk) +{ + u32 div, tmp, rate; + + div = __raw_readl(CLKPWR_MS_CTRL(CLKPWR_IOBASE)); + tmp = div & CLKPWR_MSCARD_SDCARD_EN; + + if (!tmp) + { + /* Clock is disabled */ + return 0; + } + + /* Get the parent clock rate */ + rate = clk->parent->get_rate(clk->parent); + + /* Get the LCD controller clock divider value */ + div = div & 0xF; + + if (!div) + { + /* Clock is disabled */ + return 0; + } + + tmp = rate / div; + + return tmp; +} +static int mmc_set_rate(struct clk *clk, u32 rate) +{ + /* If rate is 0, disable clock */ + if (rate == 0) + { + mmc_onoff_enable(clk, 0); + } + else + { + mmc_onoff_enable(clk, 1); + } + + return 0; +} +struct clk clk_mmc = +{ + .owner = NULL, + .name = "MCLK", + .parent = &clk_armpll, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &mmc_set_rate, + .set_parent = NULL, + .round_rate = &local_onoff_round_rate, + .get_rate = &mmc_get_rate, + .enable = &mmc_onoff_enable, + .enable_reg = CLKPWR_MS_CTRL(CLKPWR_IOBASE), + .enable_mask = CLKPWR_MSCARD_SDCARD_EN, +}; +#endif +#if defined (CONFIG_LPC32XX_MII) +struct clk clk_net = +{ + .owner = NULL, + .name = "net_ck", + .parent = &clk_hclk, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &local_onoff_set_rate, + .set_parent = NULL, + .round_rate = &local_onoff_round_rate, + .get_rate = &local_get_periph_rate, + .enable = &local_onoff_enable, + .enable_reg = CLKPWR_MACCLK_CTRL(CLKPWR_IOBASE), + .enable_mask = (CLKPWR_MACCTRL_DMACLK_EN | CLKPWR_MACCTRL_MMIOCLK_EN | CLKPWR_MACCTRL_HRCCLK_EN), +}; +#endif +#if defined (CONFIG_FB_ARMCLCD) +static u32 clcd_get_rate(struct clk *clk) +{ + u32 tmp, div, rate; + + tmp = __raw_readl(CLKPWR_LCDCLK_CTRL(CLKPWR_IOBASE)) & + CLKPWR_LCDCTRL_CLK_EN; + + if (!tmp) + { + /* Clock is disabled */ + return 0; + } + + /* Get the parent clock rate */ + rate = clk->parent->get_rate(clk->parent); + + /* Get the LCD controller clock divider value */ + tmp = __raw_readl(CLCD_POL(io_p2v(LCD_BASE))); + + /* Only supports internal clocking */ + if (tmp & CLCDC_LCDTIMING2_BCD) + { + /* No divider, LCD clock rate is parent rate */ + return rate; + } + + div = (tmp & 0x1F) | ((tmp & 0xF8) >> 22); + tmp = rate / (2 + div); + + return tmp; +} +static int clcd_set_rate(struct clk *clk, u32 rate) +{ + u32 tmp, prate, div; + + /* Get the LCD controller clock divider value */ + tmp = __raw_readl(CLCD_POL(io_p2v(LCD_BASE))); + + /* Get parent clock rate */ + prate = clk->parent->get_rate(clk->parent); + + /* If rate is 0, disable clock */ + if (rate == 0) + { + local_onoff_enable(clk, 0); + } + /* If rate is the parent rate, then just set divider bypass */ + else if (rate == prate) + { + tmp |= CLCDC_LCDTIMING2_BCD; + local_onoff_enable(clk, 1); + } + else + { + /* Find closest divider */ + div = prate / rate; + if (div == 1) + { + /* Divide by 2 */ + div = 0; + } + else + { + /* adjust for built-in /2 divider */ + div -= 2; + } + + tmp &= ~(0xF800001F); + tmp &= ~CLCDC_LCDTIMING2_BCD; + tmp |= (div & 0x1F); + tmp |= (((div >> 5) & 0x1F) << 27); + __raw_writel(tmp, CLCD_POL(io_p2v(LCD_BASE))); + local_onoff_enable(clk, 1); + } + + return 0; +} +struct clk clk_lcd = +{ + .owner = NULL, + .name = "CLCDCLK", + .parent = &clk_hclk, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &clcd_set_rate, + .set_parent = NULL, + .round_rate = &local_onoff_round_rate, + .get_rate = &clcd_get_rate, + .enable = &local_onoff_enable, + .enable_reg = CLKPWR_LCDCLK_CTRL(CLKPWR_IOBASE), + .enable_mask = CLKPWR_LCDCTRL_CLK_EN, +}; +#endif +#if defined (CONFIG_USB_GADGET_LPC32XX) +struct clk clk_usbd = +{ + .owner = NULL, + .name = "ck_usbd", + .parent = &clk_usbpll, + .rate = 0, + .flags = 0, + .usecount = 0, + .set_rate = &local_onoff_set_rate, + .set_parent = NULL, + .round_rate = &local_onoff_round_rate, + .get_rate = &local_get_periph_rate, + .enable = &local_onoff_enable, + .enable_reg = CLKPWR_USB_CTRL(CLKPWR_IOBASE), + .enable_mask = CLKPWR_USBCTRL_HCLK_EN, +}; +#endif + +/* + * System and peripheral clocks + */ +static struct clk *chip_clks[] = { + &osc_32KHz, + &osc_pll397, + &osc_main, + &clk_sys, + &clk_armpll, + &clk_hclk, + &clk_pclk, + &clk_usbpll, + &clk_timer0, + &clk_timer1, + &clk_timer2, + &clk_timer3, + &clk_vfp9, + &clk_dma, +#if defined (CONFIG_LPC32XX_WATCHDOG) + &clk_wdt, +#endif +#if defined (CONFIG_MACH_LPC32XX_UART3_ENABLE) + &clk_uart3, +#endif +#if defined (CONFIG_MACH_LPC32XX_UART4_ENABLE) + &clk_uart4, +#endif +#if defined (CONFIG_MACH_LPC32XX_UART5_ENABLE) + &clk_uart5, +#endif +#if defined (CONFIG_MACH_LPC32XX_UART6_ENABLE) + &clk_uart6, +#endif +#if defined (CONFIG_MACH_LPC32XX_I2C0_ENABLE) + &clk_i2c0, +#endif +#if defined (CONFIG_MACH_LPC32XX_I2C1_ENABLE) + &clk_i2c1, +#endif +#if defined (CONFIG_MACH_LPC32XX_USBOTG_I2C_ENABLE) + &clk_i2c2, +#endif +#if defined(CONFIG_SPI_LPC32XX) +#if defined(CONFIG_MACH_LPC32XX_SSP0_ENABLE) + &clk_ssp0, +#endif +#if defined(CONFIG_MACH_LPC32XX_SSP1_ENABLE) + &clk_ssp1, +#endif +#endif +#if defined(CONFIG_KEYBOARD_LPC32XX) + &clk_kscan, +#endif +#if defined(CONFIG_MTD_NAND_SLC_LPC32XX) + &clk_nand, +#endif +#if defined(CONFIG_SND_LPC3XXX_SOC_I2S) + &clk_i2s0, + &clk_i2s1, +#endif +#if defined (CONFIG_TOUCHSCREEN_LPC32XX) + &clk_tsc, +#endif +#if defined (CONFIG_MMC_ARMMMCI) + &clk_mmc, +#endif +#if defined (CONFIG_LPC32XX_MII) + &clk_net, +#endif +#if defined (CONFIG_FB_ARMCLCD) + &clk_lcd, +#endif +#if defined (CONFIG_USB_GADGET_LPC32XX) + &clk_usbd, +#endif +}; + +static inline void clk_lock(void) +{ + local_irq_disable(); +} + +static inline void clk_unlock(void) +{ + local_irq_enable(); +} + +struct clk *local_clk_get(struct device *dev, const char *id) +{ + struct clk *p, *clk = ERR_PTR(-ENOENT); +#if 0 +// FIXME - LISTS are not correctly working beyond a certain size + list_for_each_entry(p, &clocks, node) + { + if ((strcmp(id, p->name) == 0) && (try_module_get(p->owner))) + { + clk = p; + goto found; + } + } +#else + int i; + + /* Check all clocks */ + for (i = 0; i < ARRAY_SIZE(chip_clks); i++) + { + p = chip_clks [i]; + if ((strcmp(id, p->name) == 0) && (try_module_get(p->owner))) + { + clk = p; + goto found; + } + } +#endif +found: + return clk; +} + +static int local_clk_enable(struct clk *clk) +{ + int ret = 0; + + + /* Enable parent clocks and update use counter for this clock */ + if (clk->parent != NULL) + { + ret = local_clk_enable(clk->parent); + } + + /* Enable clock if necessary */ + if (clk->usecount == 0) + { + clk->enable(clk, 1); + } + + /* Increment use count for this clock */ + clk->usecount++; + + return ret; +} + +static int local_clk_disable(struct clk *clk) +{ + int ret = 0; + + /* Decrement use count for this clock */ + clk->usecount--; + + /* Disable clock if no other devices are using it */ + if (clk->usecount == 0) + { + clk->enable(clk, 0); + } + + /* Disable parent clocks and update use there use counters */ + if ((clk->parent != NULL) && (ret == 0)) + { + ret = local_clk_disable(clk->parent); + } + + return ret; +} + +unsigned long local_clk_get_rate(struct clk *clk) +{ + if (clk->rate != 0) + { + return clk->rate; + } + + if (clk->get_rate != NULL) + { + return (clk->get_rate)(clk); + } + + if (clk->parent != NULL) + { + return local_clk_get_rate(clk->parent); + } + + return 0; +} + +/* + * clk_get - lookup and obtain a reference to a clock producer. + */ +struct clk *clk_get(struct device *dev, const char *id) +{ + struct clk *clk; + + clk_lock(); + clk = local_clk_get(dev, id); + clk_unlock(); + + return clk; +} + +/* + * clk_enable - inform the system when the clock source should be running. + */ +int clk_enable(struct clk *clk) +{ + int ret; + + if ((IS_ERR(clk)) || (clk == NULL)) + { + return -ENODEV; + } + + clk_lock(); + ret = local_clk_enable(clk); + clk_unlock(); + + return ret; +} + +/* + * clk_disable - inform the system when the clock source is no longer required. + */ +void clk_disable(struct clk *clk) +{ + if ((IS_ERR(clk)) || (clk == NULL)) + { + return; + } + + clk_lock(); + local_clk_disable(clk); + clk_unlock(); +} + +/* + * clk_get_rate - obtain the current clock rate (in Hz) for a clock source. + * This is only valid once the clock source has been enabled. + */ +unsigned long clk_get_rate(struct clk *clk) +{ + unsigned long rate = 0; + + if (!IS_ERR(clk)) + { + rate = local_clk_get_rate(clk); + } + + return rate; +} + +/* + * clk_put - "free" the clock source + */ +void clk_put(struct clk *clk) +{ + module_put(clk->owner); +} + +/* + * clk_round_rate - adjust a rate to the exact rate a clock can provide + */ +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + if (!IS_ERR(clk)) + { + clk_lock(); + rate = clk->round_rate(clk, rate); + clk_unlock(); + } + else + { + rate = 0; + } + + return rate; +} + +/* + * clk_set_rate - set the clock rate for a clock source + */ +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + int ret = -ENODEV; + + if (!IS_ERR(clk)) + { + clk_lock(); + ret = (clk->set_rate)(clk, rate); + clk_unlock(); + } + + return ret; +} + +/* + * clk_set_parent - set the parent clock source for this clock + */ +int clk_set_parent(struct clk *clk, struct clk *parent) +{ + int ret = -ENODEV; + + if (!IS_ERR(clk)) + { + if (!clk->set_parent) + { + clk_lock(); + ret = clk->set_parent(clk, parent); + clk_unlock(); + } + } + + return ret; +} + +/* + * clk_get_parent - get the parent clock source for this clock + */ +struct clk *clk_get_parent(struct clk *clk) +{ + return clk->parent; +} + +int clk_register(struct clk *clk) +{ + clk_lock(); + list_add(&clk->node, &clocks); + clk_unlock(); + return 0; +} + +void clk_unregister(struct clk *clk) +{ + clk_lock(); + list_del(&clk->node); + clk_unlock(); +} + +EXPORT_SYMBOL(clk_get); +EXPORT_SYMBOL(clk_disable); +EXPORT_SYMBOL(clk_enable); +EXPORT_SYMBOL(clk_get_rate); +EXPORT_SYMBOL(clk_put); +EXPORT_SYMBOL(clk_round_rate); +EXPORT_SYMBOL(clk_set_rate); +EXPORT_SYMBOL(clk_set_parent); +EXPORT_SYMBOL(clk_get_parent); +EXPORT_SYMBOL(clk_register); +EXPORT_SYMBOL(clk_unregister); + +static void clk_inc_counts(struct clk *clk) +{ + clk->usecount++; + + if (clk->parent != NULL) + { + clk_inc_counts(clk->parent); + } +} + +int clk_is_sysclk_mainosc(void) +{ + u32 reg; + + /* Update PLL397 or main osc use count and parent based on + current SYSCLK selection */ + reg = __raw_readl(CLKPWR_SYSCLK_CTRL(CLKPWR_IOBASE)); + if ((reg & CLKPWR_SYSCTRL_SYSCLKMUX) == 0) + { + return 1; + } + + return 0; +} + +int __init clk_init(void) +{ + u32 reg; + int i; + + /* Register all clocks */ + for (i = 0; i < ARRAY_SIZE(chip_clks); i++) + { + clk_register(chip_clks[i]); + } + + /* Set initial rates for PLL397 and main oscillator */ + reg = __raw_readl(CLKPWR_PLL397_CTRL(CLKPWR_IOBASE)); + if ((reg & CLKPWR_SYSCTRL_PLL397_DIS) != 0) + { + osc_pll397.rate = 0; + } + else + { + osc_pll397.rate = 397 * osc_32KHz.rate; + clk_inc_counts(&osc_32KHz); + } + reg = __raw_readl(CLKPWR_MAIN_OSC_CTRL(CLKPWR_IOBASE)); + if ((reg & CLKPWR_MOSC_DISABLE) != 0) + { + osc_main.rate = 0; + } + else + { + osc_main.rate = MAIN_OSC_FREQ; + } + + /* Update PLL397 or main osc use count and parent based on + current SYSCLK selection */ + if (clk_is_sysclk_mainosc() != 0) + { + /* Main oscillator used as SYSCLK source */ + clk_sys.parent = &osc_main; + } + else + { + /* PLL397 used as SYSCLK soource */ + clk_sys.parent = &osc_pll397; + } + clk_sys.rate = clk_sys.parent->rate; + + /* Compute the ARM PLL and USB PLL frequencies */ + local_update_armpll_rate(); + local_update_usbpll_rate(); + if (clk_usbpll.rate != 0) + { + /* Based on main oscillator rate */ + clk_inc_counts(&osc_main); + } + + /* HCLK and PCLKs are always on and use the ARM PLL clock*/ + clk_inc_counts(clk_hclk.parent); + clk_inc_counts(clk_pclk.parent); + + /* Timer 0 is used for the system clock tick. It was pre-initialized + prior to this elsewhere */ + clk_inc_counts(clk_timer0.parent); + +#ifdef CLKDEBUG + for (i = 0; i < ARRAY_SIZE(chip_clks); i++) + { + struct clk *clkp = chip_clks[i]; + + pr_debug("%s: clock %s, rate %ld(Hz) Users:%d\n", + __func__, clkp->name, local_clk_get_rate(clkp), + clkp->usecount); + } +#endif + + return 0; +} + diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/dma-lpc32xx.c linux-2.6.27.8/arch/arm/mach-lpc32xx/dma-lpc32xx.c --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/dma-lpc32xx.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/dma-lpc32xx.c 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,613 @@ +/* + * linux/arch/arm/mach-lpc32xx/ma-lpc32xx.c + * + * Copyright (C) 2008 NXP Semiconductors + * (Based on parts of the PNX4008 DMA driver) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define DMAIOBASE io_p2v(DMA_BASE) +#define VALID_CHANNEL(c) (((c) >= 0) && ((c) < MAX_DMA_CHANNELS)) + +static DEFINE_SPINLOCK(dma_lock); + +struct dma_channel { + char *name; + void (*irq_handler) (int, int, void *); + void *data; + struct dma_config *dmacfg; + u32 control; + u32 config; + u32 config_int_mask; + + int list_entries; + u32 vlist, plist; + volatile u32 list_head, list_tail, list_last; + volatile u32 list_size, buffers_free; + volatile u32 prevplist; +}; + +struct dma_control { + struct clk *clk; + int num_clks; + struct dma_channel dma_channels[MAX_DMA_CHANNELS]; +}; +static struct dma_control dma_ctrl; + +static inline void __dma_regs_lock(void) +{ + spin_lock_irq(&dma_lock); +} + +static inline void __dma_regs_unlock(void) +{ + spin_unlock_irq(&dma_lock); +} + +static inline void __dma_enable(int ch) { + u32 ch_cfg = __raw_readl(DMACH_CONFIG_CH(DMAIOBASE, ch)); + ch_cfg |= DMAC_CHAN_ENABLE; + __raw_writel(ch_cfg, DMACH_CONFIG_CH(DMAIOBASE, ch)); +} + +static inline void __dma_disable(int ch) { + u32 ch_cfg = __raw_readl(DMACH_CONFIG_CH(DMAIOBASE, ch)); + ch_cfg &= ~DMAC_CHAN_ENABLE; + __raw_writel(ch_cfg, DMACH_CONFIG_CH(DMAIOBASE, ch)); +} + +static void dma_clocks_up(void) +{ + /* Enable DMA clock if needed */ + if (dma_ctrl.num_clks == 0) + { + clk_enable(dma_ctrl.clk); + __raw_writel(DMAC_CTRL_ENABLE, DMA_CONFIG(DMAIOBASE)); + } + + dma_ctrl.num_clks++; +} + +static void dma_clocks_down(void) +{ + dma_ctrl.num_clks--; + + /* Disable DMA clock if needed */ + if (dma_ctrl.num_clks == 0) + { + __raw_writel(0, DMA_CONFIG(DMAIOBASE)); + clk_disable(dma_ctrl.clk); + } +} + +static int lpc32xx_ch_setup(int ch) +{ + u32 tmpctrl, tmpcfg, tmp = 1 << ch; + + /* Channel control setup */ + tmpctrl = 0; + switch (dma_ctrl.dma_channels[ch].dmacfg->src_size) + { + case 1: + tmpctrl |= DMAC_CHAN_SRC_WIDTH_8; + break; + + case 2: + tmpctrl |= DMAC_CHAN_SRC_WIDTH_16; + break; + + case 4: + tmpctrl |= DMAC_CHAN_SRC_WIDTH_32; + break; + + default: + return -EINVAL; + } + switch (dma_ctrl.dma_channels[ch].dmacfg->dst_size) + { + case 1: + tmpctrl |= DMAC_CHAN_DEST_WIDTH_8; + break; + + case 2: + tmpctrl |= DMAC_CHAN_DEST_WIDTH_16; + break; + + case 4: + tmpctrl |= DMAC_CHAN_DEST_WIDTH_32; + break; + + default: + return -EINVAL; + } + if (dma_ctrl.dma_channels[ch].dmacfg->src_inc != 0) + { + tmpctrl |= DMAC_CHAN_SRC_AUTOINC; + } + if (dma_ctrl.dma_channels[ch].dmacfg->dst_inc != 0) + { + tmpctrl |= DMAC_CHAN_DEST_AUTOINC; + } + if (dma_ctrl.dma_channels[ch].dmacfg->src_ahb1 != 0) + { + tmpctrl |= DMAC_CHAN_SRC_AHB1; + } + if (dma_ctrl.dma_channels[ch].dmacfg->dst_ahb1 != 0) + { + tmpctrl |= DMAC_CHAN_DEST_AHB1; + } + if (dma_ctrl.dma_channels[ch].dmacfg->tc_inten != 0) + { + tmpctrl |= DMAC_CHAN_INT_TC_EN; + } + tmpctrl |= dma_ctrl.dma_channels[ch].dmacfg->src_bsize | + dma_ctrl.dma_channels[ch].dmacfg->dst_bsize; + dma_ctrl.dma_channels[ch].control = tmpctrl; + + /* Channel config setup */ + tmpcfg = dma_ctrl.dma_channels[ch].dmacfg->src_prph | + dma_ctrl.dma_channels[ch].dmacfg->dst_prph | + dma_ctrl.dma_channels[ch].dmacfg->flowctrl; + dma_ctrl.dma_channels[ch].config = tmpcfg; + + dma_ctrl.dma_channels[ch].config_int_mask = 0; + if (dma_ctrl.dma_channels[ch].dmacfg->err_inten != 0) + { + dma_ctrl.dma_channels[ch].config_int_mask |= + DMAC_CHAN_IE; + } + if (dma_ctrl.dma_channels[ch].dmacfg->tc_inten != 0) + { + dma_ctrl.dma_channels[ch].config_int_mask |= + DMAC_CHAN_ITC; + } + + tmp = __raw_readl(DMACH_CONFIG_CH(DMAIOBASE, ch)); + tmp &= ~DMAC_CHAN_ENABLE; + __raw_writel(tmp, DMACH_CONFIG_CH(DMAIOBASE, ch)); + + /* Clear interrupts for channel */ + __raw_writel((1 << ch), DMA_INT_TC_CLEAR(DMAIOBASE)); + __raw_writel((1 << ch), DMA_INT_ERR_CLEAR(DMAIOBASE)); + + /* Write control and config words */ + __raw_writel(tmpctrl, DMACH_CONTROL(DMAIOBASE, ch)); + __raw_writel(tmpcfg, DMACH_CONFIG_CH(DMAIOBASE, ch)); + + return 0; +} + +int lpc32xx_dma_ch_enable(int ch) +{ + if (!VALID_CHANNEL(ch) || !dma_ctrl.dma_channels[ch].name) + return -EINVAL; + + __dma_regs_lock(); + __dma_enable(ch); + __dma_regs_unlock(); + + return 0; +} +EXPORT_SYMBOL_GPL(lpc32xx_dma_ch_enable); + +int lpc32xx_dma_ch_disable(int ch) +{ + if (!VALID_CHANNEL(ch) || !dma_ctrl.dma_channels[ch].name) + return -EINVAL; + + __dma_regs_lock(); + __dma_disable(ch); + __dma_regs_unlock(); + + return 0; +} +EXPORT_SYMBOL_GPL(lpc32xx_dma_ch_disable); + +int lpc32xx_dma_ch_get(struct dma_config *dmachcfg, char *name, + void *irq_handler, void *data) { + int ret; + + if (!VALID_CHANNEL(dmachcfg->ch)) + return -EINVAL; + + /* If the channel is already enabled, return */ + if (dma_ctrl.dma_channels[dmachcfg->ch].name != NULL) + return -ENODEV; + + /* Save channel data */ + dma_ctrl.dma_channels[dmachcfg->ch].dmacfg = dmachcfg; + dma_ctrl.dma_channels[dmachcfg->ch].name = name; + dma_ctrl.dma_channels[dmachcfg->ch].irq_handler = irq_handler; + dma_ctrl.dma_channels[dmachcfg->ch].data = data; + + /* Setup channel */ + __dma_regs_lock(); + dma_clocks_up(); + ret = lpc32xx_ch_setup(dmachcfg->ch); + __dma_regs_unlock(); + + return ret; +} +EXPORT_SYMBOL_GPL(lpc32xx_dma_ch_get); + +int lpc32xx_dma_ch_put(int ch) +{ + u32 tmp; + + if (!VALID_CHANNEL(ch)) + return -EINVAL; + + /* If the channel is already disabled, return */ + if (dma_ctrl.dma_channels[ch].name == NULL) + return -EINVAL; + + tmp = __raw_readl(DMACH_CONFIG_CH(DMAIOBASE, ch)); + tmp &= ~DMAC_CHAN_ENABLE; + __raw_writel(tmp, DMACH_CONFIG_CH(DMAIOBASE, ch)); + + __dma_regs_lock(); + lpc32xx_dma_ch_disable(ch); + dma_clocks_down(); + __dma_regs_unlock(); + + dma_ctrl.dma_channels[ch].name = NULL; + + return 0; +} +EXPORT_SYMBOL_GPL(lpc32xx_dma_ch_put); + +int lpc32xx_dma_start_pflow_xfer(int ch, + void *src, + void *dst, + int enable) +{ + u32 tmp; + + if ((!VALID_CHANNEL(ch)) || (dma_ctrl.dma_channels[ch].name == NULL)) + return -EINVAL; + + /* When starting a DMA transfer where the peripheral is the flow + controller, DMA must be previously disabled */ + tmp = __raw_readl(DMACH_CONFIG_CH(DMAIOBASE, ch)); + if (tmp & DMAC_CHAN_ENABLE) + return -EBUSY; + + __dma_regs_lock(); + __raw_writel((u32) src, DMACH_SRC_ADDR(DMAIOBASE, ch)); + __raw_writel((u32) dst, DMACH_DEST_ADDR(DMAIOBASE, ch)); + __raw_writel(0, DMACH_LLI(DMAIOBASE, ch)); + __raw_writel(dma_ctrl.dma_channels[ch].control, DMACH_CONTROL(DMAIOBASE, ch)); + + tmp = dma_ctrl.dma_channels[ch].config | + dma_ctrl.dma_channels[ch].config_int_mask; + if (enable != 0) + tmp |= DMAC_CHAN_ENABLE; + __raw_writel(tmp, DMACH_CONFIG_CH(DMAIOBASE, ch)); + + __dma_regs_unlock(); + + return 0; +} +EXPORT_SYMBOL_GPL(lpc32xx_dma_start_pflow_xfer); + +u32 lpc32xx_dma_alloc_llist(int ch, + int entries) { + dma_addr_t dma_handle; + + if ((!VALID_CHANNEL(ch)) || (dma_ctrl.dma_channels[ch].name == NULL)) + return 0; + + /* Limit number of list entries */ + if (entries < 1) { + entries = 1; + } + if (entries > 256) { + entries = 256; + } + + /* Save list information */ + dma_ctrl.dma_channels[ch].list_entries = entries; + dma_ctrl.dma_channels[ch].list_size = (entries * DMA_LL_SIZE); + dma_ctrl.dma_channels[ch].buffers_free = entries; + dma_ctrl.dma_channels[ch].vlist = (u32) dma_alloc_coherent(NULL, + (entries * DMA_LL_SIZE), &dma_handle, GFP_KERNEL); + dma_ctrl.dma_channels[ch].plist = (u32) dma_handle; + dma_ctrl.dma_channels[ch].list_head = dma_ctrl.dma_channels[ch].vlist; + dma_ctrl.dma_channels[ch].list_tail = dma_ctrl.dma_channels[ch].vlist; + dma_ctrl.dma_channels[ch].list_last = dma_ctrl.dma_channels[ch].vlist + + dma_ctrl.dma_channels[ch].list_size; + + return dma_ctrl.dma_channels[ch].vlist; +} +EXPORT_SYMBOL_GPL(lpc32xx_dma_alloc_llist); + +void lpc32xx_dma_dealloc_llist(int ch) { + + if ((!VALID_CHANNEL(ch)) || (dma_ctrl.dma_channels[ch].name == NULL) || + (dma_ctrl.dma_channels[ch].vlist == 0)) + return; + + dma_free_coherent(NULL, dma_ctrl.dma_channels[ch].list_size, + (void *) dma_ctrl.dma_channels[ch].vlist, + (dma_addr_t) dma_ctrl.dma_channels[ch].plist); + dma_ctrl.dma_channels[ch].list_head = 0; + dma_ctrl.dma_channels[ch].list_tail = 0; + dma_ctrl.dma_channels[ch].buffers_free = 0; +} +EXPORT_SYMBOL_GPL(lpc32xx_dma_dealloc_llist); + +extern u32 lpc32xx_dma_llist_v_to_p(int ch, + u32 vlist) { + u32 pptr; + + if ((!VALID_CHANNEL(ch)) || (dma_ctrl.dma_channels[ch].name == NULL) || + (dma_ctrl.dma_channels[ch].vlist == 0)) + return 0; + + pptr = vlist - dma_ctrl.dma_channels[ch].vlist; + pptr += dma_ctrl.dma_channels[ch].plist; + + return pptr; +} +EXPORT_SYMBOL_GPL(lpc32xx_dma_llist_v_to_p); + +u32 lpc32xx_dma_llist_p_to_v(int ch, + u32 plist) { + u32 vptr; + + if ((!VALID_CHANNEL(ch)) || (dma_ctrl.dma_channels[ch].name == NULL) || + (dma_ctrl.dma_channels[ch].vlist == 0)) + return 0; + + vptr = plist - dma_ctrl.dma_channels[ch].plist; + vptr += dma_ctrl.dma_channels[ch].vlist; + + return vptr; +} +EXPORT_SYMBOL_GPL(lpc32xx_dma_llist_p_to_v); + +extern u32 lpc32xx_dma_get_llist_head(int ch) { + if ((!VALID_CHANNEL(ch)) || (dma_ctrl.dma_channels[ch].name == NULL) || + (dma_ctrl.dma_channels[ch].vlist == 0)) + return 0; + + /* Return the current list pointer (virtual) for the + DMA channel */ + return lpc32xx_dma_llist_p_to_v(ch, + __raw_readl(DMACH_LLI(DMAIOBASE, ch))); +} +EXPORT_SYMBOL_GPL(lpc32xx_dma_get_llist_head); + +extern void lpc32xx_dma_flush_llist(int ch) { + if ((!VALID_CHANNEL(ch)) || (dma_ctrl.dma_channels[ch].name == NULL) || + (dma_ctrl.dma_channels[ch].vlist == 0)) + return; + + /* Disable channel and clear LLI */ + __dma_regs_lock(); + __dma_disable(ch); + __raw_writel(0, DMACH_LLI(DMAIOBASE, ch)); + __dma_regs_unlock(); + + dma_ctrl.dma_channels[ch].list_head = dma_ctrl.dma_channels[ch].vlist; + dma_ctrl.dma_channels[ch].list_tail = dma_ctrl.dma_channels[ch].vlist; + dma_ctrl.dma_channels[ch].buffers_free = + dma_ctrl.dma_channels[ch].list_entries; +} +EXPORT_SYMBOL_GPL(lpc32xx_dma_flush_llist); + +u32 lpc32xx_dma_queue_llist_entry(int ch, + void *src, + void *dst, + int size) { + u32 tmp, plist, curhead, ctrl, cfg; + + /* Exit if all the buffers are used */ + if (dma_ctrl.dma_channels[ch].buffers_free == 0) { + return 0; + } + + curhead = dma_ctrl.dma_channels[ch].list_head; + + /* Adjust size to number of transfers (vs bytes) */ + size = size / dma_ctrl.dma_channels[ch].dmacfg->dst_size; + + /* Setup control and config words */ + ctrl = dma_ctrl.dma_channels[ch].control | size; + cfg = dma_ctrl.dma_channels[ch].config | DMAC_CHAN_ENABLE | + dma_ctrl.dma_channels[ch].config_int_mask; + + /* Populate DMA linked data structure */ + __raw_writel((u32) src, DMA_LL_SRC(curhead)); + __raw_writel((u32) dst, DMA_LL_DEST(curhead)); + __raw_writel(0, DMA_LL_NEXT_LLI(curhead)); + __raw_writel(ctrl, DMA_LL_NEXT_CTRL(curhead)); + + __dma_regs_lock(); + + /* Append link to the end of the list */ + plist = lpc32xx_dma_llist_v_to_p(ch, curhead); + if (dma_ctrl.dma_channels[ch].buffers_free < + dma_ctrl.dma_channels[ch].list_entries) { + __raw_writel(plist, dma_ctrl.dma_channels[ch].prevplist); + } + dma_ctrl.dma_channels[ch].prevplist = + DMA_LL_NEXT_LLI(lpc32xx_dma_llist_p_to_v(ch, plist)); + + /* Decrement available buffers */ + dma_ctrl.dma_channels[ch].buffers_free--; + + /* The passed buffer needs to be placed into the channel + registers and transfer should start if DMA is disabled. */ + tmp = __raw_readl(DMACH_CONFIG_CH(DMAIOBASE, ch)); + if ((tmp & DMAC_CHAN_ENABLE) == 0) { + /* DMA is disabled, so move the current buffer into the + channel registers and start transfer */ + __raw_writel((u32) src, DMACH_SRC_ADDR(DMAIOBASE, ch)); + __raw_writel((u32) dst, DMACH_DEST_ADDR(DMAIOBASE, ch)); + __raw_writel(0, DMACH_LLI(DMAIOBASE, ch)); + __raw_writel(ctrl, DMACH_CONTROL(DMAIOBASE, ch)); + __raw_writel(cfg, DMACH_CONFIG_CH(DMAIOBASE, ch)); + dma_ctrl.dma_channels[ch].prevplist = DMACH_LLI(DMAIOBASE, ch); + } + + /* Next available link */ + dma_ctrl.dma_channels[ch].list_head += DMA_LL_SIZE; + if (dma_ctrl.dma_channels[ch].list_head >= + dma_ctrl.dma_channels[ch].list_last) { + dma_ctrl.dma_channels[ch].list_head = + dma_ctrl.dma_channels[ch].vlist; + } + + __dma_regs_unlock(); + + return curhead; +} +EXPORT_SYMBOL_GPL(lpc32xx_dma_queue_llist_entry); + +extern u32 lpc32xx_get_free_llist_entry(int ch) { + u32 retplist, curplist; + + if ((!VALID_CHANNEL(ch)) || (dma_ctrl.dma_channels[ch].name == NULL) || + (dma_ctrl.dma_channels[ch].vlist == 0)) + return 0; + + /* Get current DMA LLI pointer */ + curplist = __raw_readl(DMACH_LLI(DMAIOBASE, ch)); + retplist = dma_ctrl.dma_channels[ch].list_tail; + + /* DMA is idle if curplist is 0 */ + if (curplist == 0) { + if (dma_ctrl.dma_channels[ch].list_entries == + dma_ctrl.dma_channels[ch].buffers_free) { + /* Nothing to process */ + return 0; + } + } + else { + /* Need to verify against end of list */ + curplist = lpc32xx_dma_llist_p_to_v(ch, curplist); + if (curplist == retplist) { + /* Currently processing an entry, exit */ + return 0; + } + } + + dma_ctrl.dma_channels[ch].list_tail += DMA_LL_SIZE; + if (dma_ctrl.dma_channels[ch].list_tail >= + dma_ctrl.dma_channels[ch].list_last) { + dma_ctrl.dma_channels[ch].list_tail = + dma_ctrl.dma_channels[ch].vlist; + } + + dma_ctrl.dma_channels[ch].buffers_free++; + return retplist; +} +EXPORT_SYMBOL_GPL(lpc32xx_get_free_llist_entry); + +static irqreturn_t dma_irq_handler(int irq, void *dev_id) +{ + int i; + unsigned long dint = __raw_readl(DMA_INT_STAT(DMAIOBASE)); + unsigned long tcint = __raw_readl(DMA_INT_TC_STAT(DMAIOBASE)); + unsigned long eint = __raw_readl(DMA_INT_ERR_STAT(DMAIOBASE)); + unsigned long i_bit; + + for (i = MAX_DMA_CHANNELS - 1; i >= 0; i--) { + i_bit = 1 << i; + if (dint & i_bit) { + struct dma_channel *channel = &dma_ctrl.dma_channels[i]; + + if (channel->name && channel->irq_handler) { + int cause = 0; + + if (eint & i_bit) + cause |= DMA_ERR_INT; + if (tcint & i_bit) + cause |= DMA_TC_INT; + channel->irq_handler(i, cause, channel->data); + } else { + /* + * IRQ for an unregistered DMA channel + */ + printk(KERN_WARNING + "spurious IRQ for DMA channel %d\n", i); + } + if (tcint & i_bit) + __raw_writel(i_bit, DMA_INT_TC_CLEAR(DMAIOBASE)); + if (eint & i_bit) + __raw_writel(i_bit, DMA_INT_ERR_CLEAR(DMAIOBASE)); + } + } + + return IRQ_HANDLED; +} + +static int __init lpc32xx_dma_init(void) +{ + int ret; + + printk(KERN_INFO "LPC32XX DMA driver\n"); + + ret = request_irq(IRQ_DMA, dma_irq_handler, 0, "DMA", NULL); + if (ret) { + printk(KERN_CRIT "Wow! Can't register IRQ for DMA\n"); + goto out; + } + + /* Get DMA clock */ + dma_ctrl.clk = clk_get(NULL, "clk_dmac"); + if (IS_ERR(dma_ctrl.clk)) { + ret = -ENODEV; + goto errout; + } + clk_enable(dma_ctrl.clk); + + /* Clear DMA controller */ + __raw_writel(1, DMA_CONFIG(DMAIOBASE)); + __raw_writel(0xFF, DMA_INT_TC_CLEAR(DMAIOBASE)); + __raw_writel(0xFF, DMA_INT_ERR_CLEAR(DMAIOBASE)); + + /* Clock is only enabled when needed to save power */ + clk_disable(dma_ctrl.clk); + + return 0; + +errout: + free_irq(IRQ_DMA, NULL); + +out: + return ret; +} +arch_initcall(lpc32xx_dma_init); + + diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/board.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/board.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/board.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/board.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,84 @@ +/* + * asm-arm/arch-lpc32xx/board.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 BOARD_H +#define BOARD_H + +#include "platform.h" +#include + +/* + * NAND platform configuration structure + */ +typedef int (*en_wp)(int); +struct lpc32XX_nand_cfg +{ + u32 wdr_clks; + u32 wwidth; + u32 whold; + u32 wsetup; + u32 rdr_clks; + u32 rwidth; + u32 rhold; + u32 rsetup; + int use16bus; /* 0 = 8-bit, !0 = not support */ + en_wp enable_write_prot; + struct mtd_partition* (*partition_info)(int, int*); +}; + +/* + * Key scanner platform configuration structure + */ +struct lpc32XX_kscan_cfg +{ + u32 matrix_sz; /* Size of matrix in XxY, ie. 3 = 3x3 */ + int *keymap; /* Pointer to key map for the scan matrix */ + u32 deb_clks; /* Debounce clocks (based on 32KHz clock) */ + u32 scan_delay; /* Scan delay (based on 32KHz clock) */ +}; + +/* + * Network configuration structure + */ +typedef int (*get_mac_f)(u8 *mac); +struct lpc32xx_net_cfg +{ + get_mac_f get_mac_addr; /* Function to get MAC address */ + int phy_irq; /* PHY IRQ number, or -1 for polling */ + u32 phy_mask; /* PHY mask value */ +}; + +/* + * SPI (via SSP) configuration data + */ +typedef int (*spi_cs_sel)(int, int); +typedef void (*spi_cs_setup)(int); +struct lpc32xx_spi_cfg +{ + int num_cs; /* Number of chip selects */ + spi_cs_setup spi_cs_setup; /* Initializes chip selects */ + spi_cs_sel spi_cs_set; /* Sets state of SPI chip select */ +}; + +#endif /* BOARD_H */ + diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/clock.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/clock.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/clock.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/clock.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,61 @@ +/* + * asm-arm/arch-lpc32xx/clock.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 __ARCH_ARM_LPC32XX_CLOCK_H__ +#define __ARCH_ARM_LPC32XX_CLOCK_H__ + +struct clk { + struct list_head node; + struct module *owner; + const char *name; /* Clock name */ + struct clk *parent; /* Parent clock */ + u32 rate; /* Rate in Hz for the clock (0 = disabled) */ + u32 flags; /* Setup flags */ + s8 usecount; /* Number of users of this clock */ + /* Required functions per clock */ + int (*set_rate) (struct clk *, u32); + u32 (*round_rate) (struct clk *, u32); + int (*enable) (struct clk *clk, int); + /* Optional functions per clock */ + int (*set_parent) (struct clk * clk, struct clk * parent); + u32 (*get_rate) (struct clk *clk); + /* Register and mask for enablings/disabling the clock, only + used when the CLK_FLAG_ST_ENAB flag is set */ + u32 enable_reg; /* Register to enable and disable associated clock */ + u32 enable_mask; /* Or mask for enable, AND ~mask for disable */ +}; + +/* Clock flags */ +#define CLK_FLAG_FIXED 0x01 /* Fixed frequency clock */ + +/* Main clocks used as parents for other clocks */ +extern struct clk osc_32KHz; +extern struct clk osc_main; +extern struct clk clk_armpll; +extern struct clk clk_usbpll; +extern struct clk clk_hclk; +extern struct clk clk_pclk; +int clk_register(struct clk *clk); +void clk_unregister(struct clk *clk); + +#endif + diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/debug-macro.S linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/debug-macro.S --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/debug-macro.S 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/debug-macro.S 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,49 @@ +/* + * asm-arm/arch-lpc32xx/debug-macro.S + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + + .macro addruart,rx + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + ldr \rx, =UART5_BASE @ physical + beq 1003f + ldr \rx, =io_p2v(UART5_BASE) @ virtual +1003: + .endm + + .macro senduart,rd,rx + str \rd, [\rx, #0] + .endm + + .macro busyuart,rd,rx +1002: ldr \rd, [\rx, #0x14] + tst \rd, #(1 << 6) + beq 1002b + .endm + + .macro waituart,rd,rx +1001: ldr \rd, [\rx, #0x14] + tst \rd, #(1 << 5) + beq 1001b + .endm diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/dma.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/dma.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/dma.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/dma.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,103 @@ +/* + * asm-arm/arch-lpc32xx/dma.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 __ASM_ARCH_DMA_H +#define __ASM_ARCH_DMA_H + +#include + +#define MAX_DMA_CHANNELS 8 + +#define DMA_CH_SDCARD_TX 0 +#define DMA_CH_SDCARD_RX 1 +#define DMA_CH_I2S_TX 2 +#define DMA_CH_I2S_RX 3 + +enum { + DMA_INT_UNKNOWN = 0, + DMA_ERR_INT = 1, + DMA_TC_INT = 2, +}; + +/* + * DMA channel control structure + */ +struct dma_config { + int ch; /* Channel # to use */ + int tc_inten; /* !0 = Enable TC interrupts for this channel */ + int err_inten; /* !0 = Enable error interrupts for this channel */ + int src_size; /* Source xfer size - must be 1, 2, or 4 */ + int src_inc; /* !0 = Enable source address increment */ + int src_ahb1; /* !0 = Use AHB1 for source transfer */ + int src_bsize; /* Source burst size (ie, DMAC_CHAN_SRC_BURST_xxx) */ + u32 src_prph; /* Source peripheral (ie, DMA_PERID_xxxx) */ + int dst_size; /* Destination xfer size - must be 1, 2, or 4 */ + int dst_inc; /* !0 = Enable destination address increment */ + int dst_ahb1; /* !0 = Use AHB1 for destination transfer */ + int dst_bsize; /* Destination burst size (ie, DMAC_CHAN_DEST_BURST_xxx) */ + u32 dst_prph; /* Destination peripheral (ie, DMA_PERID_xxxx) */ + u32 flowctrl; /* Flow control (ie, DMAC_CHAN_FLOW_xxxxxx) */ +}; + +/* + * Channel enable and disable functions + */ +extern int lpc32xx_dma_ch_enable(int ch); +extern int lpc32xx_dma_ch_disable(int ch); + +/* + * Channel allocation and deallocation functions + */ +extern int lpc32xx_dma_ch_get(struct dma_config *dmachcfg, + char *name, + void *irq_handler, + void *data); +extern int lpc32xx_dma_ch_put(int ch); + +/* + * Setup or start an unbound DMA transfer + */ +extern int lpc32xx_dma_start_pflow_xfer(int ch, + void *src, + void *dst, + int enable); + +/* + * DMA linked list support + */ +extern u32 lpc32xx_dma_alloc_llist(int ch, + int entries); +extern void lpc32xx_dma_dealloc_llist(int ch); +extern u32 lpc32xx_dma_llist_v_to_p(int ch, + u32 vlist); +extern u32 lpc32xx_dma_llist_p_to_v(int ch, + u32 plist); +extern u32 lpc32xx_dma_get_llist_head(int ch); +extern void lpc32xx_dma_flush_llist(int ch); +extern u32 lpc32xx_dma_queue_llist_entry(int ch, + void *src, + void *dst, + int size); +extern u32 lpc32xx_get_free_llist_entry(int ch); + +#endif /* _ASM_ARCH_DMA_H */ + diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/entry-macro.S linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/entry-macro.S --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/entry-macro.S 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/entry-macro.S 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,83 @@ +/* + * asm-arm/arch-lpc32xx/entry-macro.S + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +/* + * Return IRQ number in irqnr. Also return processor Z flag status in CPSR + * as set if an interrupt is pending. + */ + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + /* Get MIC status first */ + ldr \base, =io_p2v(MIC_BASE) + ldr \irqstat, [\base, #INTC_STAT] + and \irqstat, \irqstat, #0xFFFFFFFC + mov \tmp, #0 + + /* If the masked IRQ status is 0, then the interrupt was due to + SIC1 or SIC2 */ + cmp \irqstat, #0 + bne 1000f + + /* Check SIC1 to see if an interrupt is pending */ + ldr \base, =io_p2v(SIC1_BASE) + ldr \irqstat, [\base, #INTC_STAT] + mov \tmp, #32 + + /* If the SIC1 status is 0, then the interrupt falls to SIC2 */ + cmp \irqstat, #0 + bne 1000f + + /* Check SIC2 to see if an interrupt is pending */ + ldr \base, =io_p2v(SIC2_BASE) + ldr \irqstat, [\base, #INTC_STAT] + mov \tmp, #64 + + /* If the SIC1 status is 0, then the interrupt falls to SIC2 */ + cmp \irqstat, #0 + beq 1001f + +1000: + clz \irqnr, \irqstat + rsb \irqnr, \irqnr, #31 + add \irqnr, \irqnr, \tmp /* Interrupt # between 0 and 95 */ + +1001: + teq \irqstat, #0 + .endm + + .macro disable_fiq + .endm + + .macro get_irqnr_preamble, base, tmp + .endm + + .macro arch_ret_to_user, tmp1, tmp2 + .endm + +// .macro irq_prio_table +// .endm + + + diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/hardware.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/hardware.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/hardware.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/hardware.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,38 @@ +/* + * asm-arm/arch-lpc32xx/hardware.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#include + +/* Start of virtual addresses for IO devices */ +#define IO_BASE 0xF0000000 + +#define io_p2v(x) (IO_BASE | (((x) & 0xff000000) >> 4) | ((x) & 0x000fffff)) +#define io_v2p(x) ((((x) & 0x0ff00000) << 4) | ((x) & 0x000fffff)) + +/* This macro relies on fact that for all HW i/o addresses bits 20-23 are 0 */ +#define IO_ADDRESS(x) (((((x) & 0xff000000) >> 4) | ((x) & 0xfffff)) | IO_BASE) + +#endif + diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/i2c.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/i2c.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/i2c.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/i2c.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,64 @@ +/* + * PNX4008-specific tweaks for I2C IP3204 block + * + * Author: Vitaly Wool + * + * 2005 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#ifndef __ASM_ARCH_I2C_H__ +#define __ASM_ARCH_I2C_H__ + +enum { + mstatus_tdi = 0x00000001, + mstatus_afi = 0x00000002, + mstatus_nai = 0x00000004, + mstatus_drmi = 0x00000008, + mstatus_active = 0x00000020, + mstatus_scl = 0x00000040, + mstatus_sda = 0x00000080, + mstatus_rff = 0x00000100, + mstatus_rfe = 0x00000200, + mstatus_tff = 0x00000400, + mstatus_tfe = 0x00000800, +}; + +enum { + mcntrl_tdie = 0x00000001, + mcntrl_afie = 0x00000002, + mcntrl_naie = 0x00000004, + mcntrl_drmie = 0x00000008, + mcntrl_daie = 0x00000020, + mcntrl_rffie = 0x00000040, + mcntrl_tffie = 0x00000080, + mcntrl_reset = 0x00000100, + mcntrl_cdbmode = 0x00000400, +}; + +enum { + rw_bit = 1 << 0, + start_bit = 1 << 8, + stop_bit = 1 << 9, +}; + +#define I2C_REG_RX(a) ((a)->ioaddr) /* Rx FIFO reg (RO) */ +#define I2C_REG_TX(a) ((a)->ioaddr) /* Tx FIFO reg (WO) */ +#define I2C_REG_STS(a) ((a)->ioaddr + 0x04) /* Status reg (RO) */ +#define I2C_REG_CTL(a) ((a)->ioaddr + 0x08) /* Ctl reg */ +#define I2C_REG_CKL(a) ((a)->ioaddr + 0x0c) /* Clock divider low */ +#define I2C_REG_CKH(a) ((a)->ioaddr + 0x10) /* Clock divider high */ +#define I2C_REG_ADR(a) ((a)->ioaddr + 0x14) /* I2C address */ +#define I2C_REG_RFL(a) ((a)->ioaddr + 0x18) /* Rx FIFO level (RO) */ +#define I2C_REG_TFL(a) ((a)->ioaddr + 0x1c) /* Tx FIFO level (RO) */ +#define I2C_REG_RXB(a) ((a)->ioaddr + 0x20) /* Num of bytes Rx-ed (RO) */ +#define I2C_REG_TXB(a) ((a)->ioaddr + 0x24) /* Num of bytes Tx-ed (RO) */ +#define I2C_REG_TXS(a) ((a)->ioaddr + 0x28) /* Tx slave FIFO (RO) */ +#define I2C_REG_STFL(a) ((a)->ioaddr + 0x2c) /* Tx slave FIFO level (RO) */ + +#define HCLK_MHZ 13 +#define I2C_CHIP_NAME "PNX4008-I2C" + +#endif /* __ASM_ARCH_I2C_H___ */ diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/io.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/io.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/io.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/io.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,32 @@ +/* + * asm-arm/arch-lpc32xx/io.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 __LPC32XX_IO_H +#define __LPC32XX_IO_H + +#define IO_SPACE_LIMIT 0xfff00000 + +#define __io(a) ((void __iomem *)(a)) +#define __mem_pci(a) (a) + +#endif + diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/irqs.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/irqs.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/irqs.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/irqs.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,145 @@ +/* + * asm-arm/arch-lpc32xx/irqs.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 __LPC32XX_IRQS_h__ +#define __LPC32XX_IRQS_h__ + +#define INTC_MASK 0x00 +#define INTC_RAW_STAT 0x04 +#define INTC_STAT 0x08 +#define INTC_POLAR 0x0C +#define INTC_ACT_TYPE 0x10 +#define INTC_TYPE 0x14 + +#define INTC_SIC1_OFFS 32 +#define INTC_SIC2_OFFS 64 + +/* + * Default value represeting the Activation polarity of all internal + * interrupt sources + */ +#define MIC_APR_DEFAULT 0x3FF0EFF8 +#define SIC1_APR_DEFAULT 0xFBD27186 +#define SIC2_APR_DEFAULT 0x801810C0 + +/* + * Default value represeting the Activation Type of all internal + * interrupt sources. All are level senesitive. + */ +#define MIC_ATR_DEFAULT 0x00000000 +#define SIC1_ATR_DEFAULT 0x00026000 +#define SIC2_ATR_DEFAULT 0x00000000 + +/* + * MIC interrupts + */ +#define IRQ_SUB1IRQ 0 +#define IRQ_SUB2IRQ 1 +#define IRQ_PWM3 3 +#define IRQ_PWM4 4 +#define IRQ_HSTIMER 5 +#define IRQ_WATCH 6 +#define IRQ_UART_IIR3 7 +#define IRQ_UART_IIR4 8 +#define IRQ_UART_IIR5 9 +#define IRQ_UART_IIR6 10 +#define IRQ_FLASH 11 +#define IRQ_SD1 13 +#define IRQ_LCD 14 +#define IRQ_SD0 15 +#define IRQ_TIMER0 16 +#define IRQ_TIMER1 17 +#define IRQ_TIMER2 18 +#define IRQ_TIMER3 19 +#define IRQ_SSP0 20 +#define IRQ_SSP1 21 +#define IRQ_I2S0 22 +#define IRQ_I2S1 23 +#define IRQ_UART_IIR7 24 +#define IRQ_UART_IIR2 25 +#define IRQ_UART_IIR1 26 +#define IRQ_MSTIMER 27 +#define IRQ_DMA 28 +#define IRQ_ETHERNET 29 +#define IRQ_SUB1FIQ 30 +#define IRQ_SUB2FIQ 31 + +/* + * SIC1 interrupts + */ +#define IRQ_JTAG_COMM_TX (INTC_SIC1_OFFS + 1) +#define IRQ_JTAG_COMM_RX (INTC_SIC1_OFFS + 2) +#define IRQ_GPI_11 (INTC_SIC1_OFFS + 4) +#define IRQ_TS_P (INTC_SIC1_OFFS + 6) +#define IRQ_TS_IRQ (INTC_SIC1_OFFS + 7) +#define IRQ_TS_AUX (INTC_SIC1_OFFS + 8) +#define IRQ_SPI2 (INTC_SIC1_OFFS + 12) +#define IRQ_PLLUSB (INTC_SIC1_OFFS + 13) +#define IRQ_PLLHCLK (INTC_SIC1_OFFS + 14) +#define IRQ_PLL397 (INTC_SIC1_OFFS + 17) +#define IRQ_I2C_2 (INTC_SIC1_OFFS + 18) +#define IRQ_I2C_1 (INTC_SIC1_OFFS + 19) +#define IRQ_RTC (INTC_SIC1_OFFS + 20) +#define IRQ_KEY (INTC_SIC1_OFFS + 22) +#define IRQ_SPI1 (INTC_SIC1_OFFS + 23) +#define IRQ_SW (INTC_SIC1_OFFS + 24) +#define IRQ_USB_OTG_TIMER (INTC_SIC1_OFFS + 25) +#define IRQ_USB_OTG_ATX (INTC_SIC1_OFFS + 26) +#define IRQ_USB_HOST (INTC_SIC1_OFFS + 27) +#define IRQ_USB_DEV_DMA (INTC_SIC1_OFFS + 28) +#define IRQ_USB_DEV_LP (INTC_SIC1_OFFS + 29) +#define IRQ_USB_DEV_HP (INTC_SIC1_OFFS + 30) +#define IRQ_USB_I2C (INTC_SIC1_OFFS + 31) + +/* + * SIC2 interrupts + */ +#define IRQ_GPIO_00 (INTC_SIC2_OFFS + 0) +#define IRQ_GPIO_01 (INTC_SIC2_OFFS + 1) +#define IRQ_GPIO_02 (INTC_SIC2_OFFS + 2) +#define IRQ_GPIO_03 (INTC_SIC2_OFFS + 3) +#define IRQ_GPIO_04 (INTC_SIC2_OFFS + 4) +#define IRQ_GPIO_05 (INTC_SIC2_OFFS + 5) +#define IRQ_SPI2_DATAIN (INTC_SIC2_OFFS + 6) +#define IRQ_U2_HCTS (INTC_SIC2_OFFS + 7) +#define IRQ_P0_P1_IRQ (INTC_SIC2_OFFS + 8) +#define IRQ_GPI_08 (INTC_SIC2_OFFS + 9) +#define IRQ_GPI_09 (INTC_SIC2_OFFS + 10) +#define IRQ_GPI_10 (INTC_SIC2_OFFS + 11) +#define IRQ_U7_HCTS (INTC_SIC2_OFFS + 12) +#define IRQ_GPI_07 (INTC_SIC2_OFFS + 15) +#define IRQ_SDIO (INTC_SIC2_OFFS + 18) +#define IRQ_U5_RX (INTC_SIC2_OFFS + 19) +#define IRQ_SPI1_DATAIN (INTC_SIC2_OFFS + 20) +#define IRQ_GPI_00 (INTC_SIC2_OFFS + 22) +#define IRQ_GPI_01 (INTC_SIC2_OFFS + 23) +#define IRQ_GPI_02 (INTC_SIC2_OFFS + 24) +#define IRQ_GPI_03 (INTC_SIC2_OFFS + 25) +#define IRQ_GPI_04 (INTC_SIC2_OFFS + 26) +#define IRQ_GPI_05 (INTC_SIC2_OFFS + 27) +#define IRQ_GPI_06 (INTC_SIC2_OFFS + 28) +#define IRQ_SYSCLK (INTC_SIC2_OFFS + 31) + +#define NR_IRQS 96 + +#endif /* __LPC32XX_IRQS_h__ */ + diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_clcdc.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_clcdc.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_clcdc.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_clcdc.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,174 @@ +/* + * asm-arm/arch-lpc32xx/lpc32xx_clcd.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 LPC32xx_CLCDC_H +#define LPC32xx_CLCDC_H + +#define _BIT(n) (1 << (n)) +#define _SBF(f,v) (((v)) << (f)) + +/********************************************************************** +* Color LCD controller register offsets +**********************************************************************/ + +#define CLCD_TIMH(x) (x + 0x000) +#define CLCD_TIMV(x) (x + 0x004) +#define CLCD_POL(x) (x + 0x008) +#define CLCD_LE(x) (x + 0x00C) +#define CLCD_UPBASE(x) (x + 0x010) +#define CLCD_LPBASE(x) (x + 0x014) +#define CLCD_CTRL(x) (x + 0x018) +#define CLCD_INTMASK(x) (x + 0x01C) +#define CLCD_INTRAW(x) (x + 0x020) +#define CLCD_INTSTAT(x) (x + 0x024) +#define CLCD_INTCLR(x) (x + 0x02C) +#define CLCD_UPCURR(x) (x + 0x030) +#define CLCD_PAL(x) (x + 0x100) +#define CLCD_CRSR_IMG(x) (x + 0x800) +#define CLCD_CRSR_CTRL(x) (x + 0xC00) +#define CLCD_CRSR_CFG(x) (x + 0xC04) +#define CLCD_CRSR_PAL0(x) (x + 0xC08) +#define CLCD_CRSR_PAL1(x) (x + 0xC0C) +#define CLCD_CRSR_XY(x) (x + 0xC10) +#define CLCD_CRSR_CLIP(x) (x + 0xC14) +#define CLCD_CRSR_INTMASK(x) (x + 0xC20) +#define CLCD_CRSR_INTCLR(x) (x + 0xC24) +#define CLCD_CRSR_INTRAW(x) (x + 0xC28) +#define CLCD_CRSR_INTSTAT(x) (x + 0xC2C) + +/*********************************************************************** + * Color LCD controller timing 0 register definitions + **********************************************************************/ + +/* LCD controller timing 0 pixel per line load macro */ +#define CLCDC_LCDTIMING0_PPL(n) _SBF(2, (((n) / 16) - 1) & 0x0000003F) +/* LCD controller timing 0 HSYNC pulse width load macro */ +#define CLCDC_LCDTIMING0_HSW(n) _SBF(8, ((n) - 1) & 0x000000FF) +/* LCD controller timing 0 horizontal front porch load macro */ +#define CLCDC_LCDTIMING0_HFP(n) _SBF(16, ((n) - 1) & 0x000000FF) +/* LCD controller timing 0 horizontal back porch load macro */ +#define CLCDC_LCDTIMING0_HBP(n) _SBF(24, ((n) - 1) & 0x000000FF) + +/*********************************************************************** + * Color LCD controller timing 1 register definitions + **********************************************************************/ + +/* LCD controller timing 1 lines per panel load macro */ +#define CLCDC_LCDTIMING1_LPP(n) _SBF(0, ((n) - 1) & 0x000003FF) +/* LCD controller timing 1 VSYNC pulse width load macro */ +#define CLCDC_LCDTIMING1_VSW(n) _SBF(10, ((n) - 1) & 0x0000003F) +/* LCD controller timing 1 vertical front porch load macro */ +#define CLCDC_LCDTIMING1_VFP(n) _SBF(16, (n & 0x000000FF)) +/* LCD controller timing 1 vertical back porch load macro */ +#define CLCDC_LCDTIMING1_VBP(n) _SBF(24, (n & 0x000000FF)) + +/*********************************************************************** + * Color LCD controller timing 2 register definitions + **********************************************************************/ + +/* LCD controller timing 2 panel clock divisor load macro */ +#define CLCDC_LCDTIMING2_PCD(n) CLCDC_LCDTIMING2_PCD_hi(n) | CLCDC_LCDTIMING2_PCD_lo(n) +#define CLCDC_LCDTIMING2_PCD_hi(n) (_SBF(22,((n) - 2 )) & 0xf8000000) +#define CLCDC_LCDTIMING2_PCD_lo(n) (_SBF(0, ((n) - 2 )) & 0x0000001f) +/* LCD controller timing 2 pixel clock selector bit */ +#define CLCDC_LCDTIMING2_CLKSEL 0x00000020 +/* LCD controller timing 2 AC bias frequency load macro */ +#define CLCDC_LCDTIMING2_ACB(n) _SBF(6, ((n) - 1) & 0x0000001F) +/* LCD controller timing 2 VSYNC invert bit */ +#define CLCDC_LCDTIMING2_IVS 0x00000800 +/* LCD controller timing 2 HSYNC invert bit */ +#define CLCDC_LCDTIMING2_IHS 0x00001000 +/* LCD controller timing 2 clock invert bit */ +#define CLCDC_LCDTIMING2_IPC 0x00002000 +/* LCD controller timing 2 output enable invert bit */ +#define CLCDC_LCDTIMING2_IOE 0x00004000 +/* LCD controller timing 2 clocks per line load macro */ +#define CLCDC_LCDTIMING2_CPL(n) _SBF(16, (n) & 0x000003FF) +/* LCD controller timing 2 bypass pixel divider bit */ +#define CLCDC_LCDTIMING2_BCD 0x04000000 + +/*********************************************************************** + * Color LCD controller interrupt enable/status register definitions + **********************************************************************/ + + +/* LCDIntrEnable, LCDInterrupt, LCDStatus FIFO underflow */ +#define CLCDC_LCDSTATUS_FUF 0x00000002 +/* LCDIntrEnable, LCDInterrupt, LCDStatus load next base bit */ +#define CLCDC_LCDSTATUS_LNBU 0x00000004 +/* LCDIntrEnable, LCDInterrupt, LCDStatus vertical compare bit */ +#define CLCDC_LCDSTATUS_VCOMP 0x00000008 +/* LCDIntrEnable, LCDInterrupt, LCDStatus aHB bus error bit */ +#define CLCDC_LCDSTATUS_MBERROR 0x00000010 + +/*********************************************************************** + * Color LCD controller control register definitions + **********************************************************************/ + +/* LCD control enable bit */ +#define CLCDC_LCDCTRL_ENABLE 0x00000001 +/* LCD control 1 bit per pixel bit field */ +#define CLCDC_LCDCTRL_BPP1 0x00000000 +/* LCD control 2 bits per pixel bit field */ +#define CLCDC_LCDCTRL_BPP2 0x00000002 +/* LCD control 4 bits per pixel bit field */ +#define CLCDC_LCDCTRL_BPP4 0x00000004 +/* LCD control 8 bits per pixel bit field */ +#define CLCDC_LCDCTRL_BPP8 0x00000006 +/* LCD control 16 bits per pixel bit field */ +#define CLCDC_LCDCTRL_BPP16 0x00000008 +/* LCD control 24 bits per pixel bit field */ +#define CLCDC_LCDCTRL_BPP24 0x0000000A +/* LCD control 16 bits per pixel bit field (565 mode) */ +#define CLCDC_LCDCTRL_BPP16_565 0x0000000C +/* LCD control 12 bits per pixel bit field */ +#define CLCDC_LCDCTRL_BPP12 0x0000000E +/* LCD control 16 bits per pixel bit field */ +#define CLCDC_LCDCTRL_BPP_MASK 0x0000000E +/* LCD control mono select bit */ +#define CLCDC_LCDCTRL_BW_MONO 0x00000010 +/* LCD controler TFT select bit */ +#define CLCDC_LCDCTRL_TFT 0x00000020 +/* LCD control monochrome LCD has 4-bit/8-bit select bit */ +#define CLCDC_LCDCTRL_MONO8 0x00000040 +/* LCD control dual panel select bit */ +#define CLCDC_LCDCTRL_DUAL 0x00000080 +/* LCD control normal RGB bit */ +#define CLCDC_LCDCTRL_RGB 0x00000100 +/* LCD control swap RGB (555 BGR mode) bit */ +#define CLCDC_LCDCTRL_BGR 0x00000000 +/* LCD control power enable bit */ +#define CLCDC_LCDCTRL_PWR 0x00000800 +/* LCD control VCOMP interrupt is start of VSYNC */ +#define CLCDC_LCDCTRL_VCOMP_VS 0x00000000 +/* LCD control VCOMP interrupt is start of back porch */ +#define CLCDC_LCDCTRL_VCOMP_BP 0x00001000 +/* LCD control VCOMP interrupt is start of video */ +#define CLCDC_LCDCTRL_VCOMP_AV 0x00002000 +/* LCD control VCOMP interrupt is start of front porch */ +#define CLCDC_LCDCTRL_VCOMP_FP 0x00003000 +/* LCD control interrupt condition bits mask */ +#define CLCDC_LCDCTRL_VCOMP_IC 0x00003000 +/* LCD control watermark is 4 or 8 words free mask */ +#define CLCDC_LCDCTRL_WATERMARK 0x00010000 + +#endif /* LPC32xx_CLCDC_H */ diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_clkpwr.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_clkpwr.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_clkpwr.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_clkpwr.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,711 @@ +/* + * asm-arm/arch-lpc32xx/lpc32xx_clkpwr.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 LPC32XX_CLKPWR_H +#define LPC32XX_CLKPWR_H + +#define _BIT(n) (1 << (n)) + +/********************************************************************** +* Clock and Power control register offsets +**********************************************************************/ + +#define CLKPWR_DEBUG_CTRL(x) (x + 0x000) +#define CLKPWR_BOOTMAP(x) (x + 0x014) +#define CLKPWR_P01_ER(x) (x + 0x018) +#define CLKPWR_USBCLK_PDIV(x) (x + 0x01C) +#define CLKPWR_INT_ER(x) (x + 0x020) +#define CLKPWR_INT_RS(x) (x + 0x024) +#define CLKPWR_INT_SR(x) (x + 0x028) +#define CLKPWR_INT_AP(x) (x + 0x02C) +#define CLKPWR_PIN_ER(x) (x + 0x030) +#define CLKPWR_PIN_RS(x) (x + 0x034) +#define CLKPWR_PIN_SR(x) (x + 0x038) +#define CLKPWR_PIN_AP(x) (x + 0x03C) +#define CLKPWR_HCLK_DIV(x) (x + 0x040) +#define CLKPWR_PWR_CTRL(x) (x + 0x044) +#define CLKPWR_PLL397_CTRL(x) (x + 0x048) +#define CLKPWR_MAIN_OSC_CTRL(x) (x + 0x04C) +#define CLKPWR_SYSCLK_CTRL(x) (x + 0x050) +#define CLKPWR_LCDCLK_CTRL(x) (x + 0x054) +#define CLKPWR_HCLKPLL_CTRL(x) (x + 0x058) +#define CLKPWR_ADC_CLK_CTRL_1(x) (x + 0x060) +#define CLKPWR_USB_CTRL(x) (x + 0x064) +#define CLKPWR_SDRAMCLK_CTRL(x) (x + 0x068) +#define CLKPWR_DDR_LAP_NOM(x) (x + 0x06C) +#define CLKPWR_DDR_LAP_COUNT(x) (x + 0x070) +#define CLKPWR_DDR_LAP_DELAY(x) (x + 0x074) +#define CLKPWR_SSP_CLK_CTRL(x) (x + 0x078) +#define CLKPWR_I2S_CLK_CTRL(x) (x + 0x07C) +#define CLKPWR_MS_CTRL(x) (x + 0x080) +#define CLKPWR_MACCLK_CTRL(x) (x + 0x090) +#define CLKPWR_TEST_CLK_SEL(x) (x + 0x0A4) +#define CLKPWR_SFW_INT(x) (x + 0x0A8) +#define CLKPWR_I2C_CLK_CTRL(x) (x + 0x0AC) +#define CLKPWR_KEY_CLK_CTRL(x) (x + 0x0B0) +#define CLKPWR_ADC_CLK_CTRL(x) (x + 0x0B4) +#define CLKPWR_PWM_CLK_CTRL(x) (x + 0x0B8) +#define CLKPWR_TIMER_CLK_CTRL(x) (x + 0x0BC) +#define CLKPWR_TIMERS_PWMS_CLK_CTRL_1(x) (x + 0x0C0) +#define CLKPWR_SPI_CLK_CTRL(x) (x + 0x0C4) +#define CLKPWR_NAND_CLK_CTRL(x) (x + 0x0C8) +#define CLKPWR_UART3_CLK_CTRL(x) (x + 0x0D0) +#define CLKPWR_UART4_CLK_CTRL(x) (x + 0x0D4) +#define CLKPWR_UART5_CLK_CTRL(x) (x + 0x0D8) +#define CLKPWR_UART6_CLK_CTRL(x) (x + 0x0DC) +#define CLKPWR_IRDA_CLK_CTRL(x) (x + 0x0E0) +#define CLKPWR_UART_CLK_CTRL(x) (x + 0x0E4) +#define CLKPWR_DMA_CLK_CTRL(x) (x + 0x0E8) +#define CLKPWR_AUTOCLOCK(x) (x + 0x0EC) + +/********************************************************************** +* clkpwr_debug_ctrl register definitions +**********************************************************************/ +/* VFP clock enable */ +#define CLKPWR_VFP_CLOCK_ENABLE_BIT _BIT(4) + +/********************************************************************** +* clkpwr_bootmap register definitions +**********************************************************************/ +/* Boot mapping at address 0x0, (0) = IROM, (1) = IRAM */ +#define CLKPWR_BOOTMAP_SEL_BIT 0x1 + +/********************************************************************** +* clkpwr_start_gpio register bit definitions +**********************************************************************/ +/* GPI/O sources bit positions for interrupt wakeup */ +#define CLKPWR_GPIOSRC_P1IO23_BIT _BIT(31) +#define CLKPWR_GPIOSRC_P1IO22_BIT _BIT(30) +#define CLKPWR_GPIOSRC_P1IO21_BIT _BIT(29) +#define CLKPWR_GPIOSRC_P1IO20_BIT _BIT(28) +#define CLKPWR_GPIOSRC_P1IO19_BIT _BIT(27) +#define CLKPWR_GPIOSRC_P1IO18_BIT _BIT(26) +#define CLKPWR_GPIOSRC_P1IO17_BIT _BIT(25) +#define CLKPWR_GPIOSRC_P1IO16_BIT _BIT(24) +#define CLKPWR_GPIOSRC_P1IO15_BIT _BIT(23) +#define CLKPWR_GPIOSRC_P1IO14_BIT _BIT(22) +#define CLKPWR_GPIOSRC_P1IO13_BIT _BIT(21) +#define CLKPWR_GPIOSRC_P1IO12_BIT _BIT(20) +#define CLKPWR_GPIOSRC_P1IO11_BIT _BIT(19) +#define CLKPWR_GPIOSRC_P1IO10_BIT _BIT(18) +#define CLKPWR_GPIOSRC_P1IO9_BIT _BIT(17) +#define CLKPWR_GPIOSRC_P1IO8_BIT _BIT(16) +#define CLKPWR_GPIOSRC_P1IO7_BIT _BIT(15) +#define CLKPWR_GPIOSRC_P1IO6_BIT _BIT(14) +#define CLKPWR_GPIOSRC_P1IO5_BIT _BIT(13) +#define CLKPWR_GPIOSRC_P1IO4_BIT _BIT(12) +#define CLKPWR_GPIOSRC_P1IO3_BIT _BIT(11) +#define CLKPWR_GPIOSRC_P1IO2_BIT _BIT(10) +#define CLKPWR_GPIOSRC_P1IO1_BIT _BIT(9) +#define CLKPWR_GPIOSRC_P1IO0_BIT _BIT(8) +#define CLKPWR_GPIOSRC_P0IO7_BIT _BIT(7) +#define CLKPWR_GPIOSRC_P0IO6_BIT _BIT(6) +#define CLKPWR_GPIOSRC_P0IO5_BIT _BIT(5) +#define CLKPWR_GPIOSRC_P0IO4_BIT _BIT(4) +#define CLKPWR_GPIOSRC_P0IO3_BIT _BIT(3) +#define CLKPWR_GPIOSRC_P0IO2_BIT _BIT(2) +#define CLKPWR_GPIOSRC_P0IO1_BIT _BIT(1) +#define CLKPWR_GPIOSRC_P0IO0_BIT _BIT(0) + +/********************************************************************** +* clkpwr_usbclk_pdiv register definitions +**********************************************************************/ +/* Macro for setting USB PLL clock predivider */ +#define CLKPWR_SET_PLL_USBPDIV(n) ((n) & 0xF) +/* Mask for USB PLL clock predivider bits */ +#define CLKPWR_USBPDIV_PLL_MASK 0xF + +/********************************************************************** +* clkpwr_start_int, clkpwr_start_raw_sts_int, clkpwr_start_sts_int, +* clkpwr_start_pol_int, register bit definitions +**********************************************************************/ +/* Internal sources bit positions for interrupt wakeup */ +#define CLKPWR_INTSRC_ADC_BIT _BIT(31) +#define CLKPWR_INTSRC_TS_P_BIT _BIT(30) +#define CLKPWR_INTSRC_TS_AUX_BIT _BIT(29) +#define CLKPWR_INTSRC_USBAHNEEDCLK_BIT _BIT(26) +#define CLKPWR_INTSRC_MSTIMER_BIT _BIT(25) +#define CLKPWR_INTSRC_RTC_BIT _BIT(24) +#define CLKPWR_INTSRC_USBNEEDCLK_BIT _BIT(23) +#define CLKPWR_INTSRC_USB_BIT _BIT(22) +#define CLKPWR_INTSRC_I2C_BIT _BIT(21) +#define CLKPWR_INTSRC_USBOTGTIMER_BIT _BIT(20) +#define CLKPWR_INTSRC_USBATXINT_BIT _BIT(19) +#define CLKPWR_INTSRC_KEY_BIT _BIT(16) +#define CLKPWR_INTSRC_MAC_BIT _BIT(7) +#define CLKPWR_INTSRC_P0P1_BIT _BIT(6) +#define CLKPWR_INTSRC_GPIO_05_BIT _BIT(5) +#define CLKPWR_INTSRC_GPIO_04_BIT _BIT(4) +#define CLKPWR_INTSRC_GPIO_03_BIT _BIT(3) +#define CLKPWR_INTSRC_GPIO_02_BIT _BIT(2) +#define CLKPWR_INTSRC_GPIO_01_BIT _BIT(1) +#define CLKPWR_INTSRC_GPIO_00_BIT _BIT(0) + +/********************************************************************** +* clkpwr_start_pin, clkpwr_start_raw_sts_pin, clkpwr_start_sts_pin, +* clkpwr_start_pol_pin register bit definitions +**********************************************************************/ +/* External sources bit positions for interrupt wakeup */ +#define CLKPWR_EXTSRC_U7_RX_BIT _BIT(31) +#define CLKPWR_EXTSRC_U7_HCTS_BIT _BIT(30) +#define CLKPWR_EXTSRC_U6_IRRX_BIT _BIT(28) +#define CLKPWR_EXTSRC_U5_RX_BIT _BIT(26) +#define CLKPWR_EXTSRC_GPI_11_BIT _BIT(25) +#define CLKPWR_EXTSRC_U3_RX_BIT _BIT(24) +#define CLKPWR_EXTSRC_U2_HCTS_BIT _BIT(23) +#define CLKPWR_EXTSRC_U2_RX_BIT _BIT(22) +#define CLKPWR_EXTSRC_U1_RX_BIT _BIT(21) +#define CLKPWR_EXTSRC_MSDIO_INT_BIT _BIT(18) +#define CLKPWR_EXTSRC_MSDIO_SRT_BIT _BIT(17) +#define CLKPWR_EXTSRC_GPIO_O6_BIT _BIT(16) +#define CLKPWR_EXTSRC_GPIO_O5_BIT _BIT(15) +#define CLKPWR_EXTSRC_GPIO_O4_BIT _BIT(14) +#define CLKPWR_EXTSRC_GPIO_O3_BIT _BIT(13) +#define CLKPWR_EXTSRC_GPIO_O2_BIT _BIT(12) +#define CLKPWR_EXTSRC_GPIO_O1_BIT _BIT(11) +#define CLKPWR_EXTSRC_GPIO_O0_BIT _BIT(10) +#define CLKPWR_EXTSRC_SYSCLKEN_BIT _BIT(9) +#define CLKPWR_EXTSRC_SPI1_DATIN_BIT _BIT(8) +#define CLKPWR_EXTSRC_GPIO_O7_BIT _BIT(7) +#define CLKPWR_EXTSRC_SPI2_DATIN_BIT _BIT(6) +#define CLKPWR_EXTSRC_GPIO_10_BIT _BIT(5) +#define CLKPWR_EXTSRC_GPIO_O9_BIT _BIT(4) +#define CLKPWR_EXTSRC_GPIO_O8_BIT _BIT(3) + +/********************************************************************** +* clkpwr_hclk_div register definitions +**********************************************************************/ +/* HCLK Divider DDRAM clock stop (used for SDRAM only) */ +#define CLKPWR_HCLKDIV_DDRCLK_STOP (0x0 << 7) +/* HCLK Divider DDRAM clock is the same speed as the ARM */ +#define CLKPWR_HCLKDIV_DDRCLK_NORM (0x1 << 7) +/* HCLK Divider DDRAM clock is half the speed as the ARM */ +#define CLKPWR_HCLKDIV_DDRCLK_HALF (0x2 << 7) +/* HCLK Divider PERIPH_CLK divider, for a value of n, the divider is + (1+n), maximum value of n is 32 */ +#define CLKPWR_HCLKDIV_PCLK_DIV(n) (((n) & 0x1F) << 2) +/* HCLK Divider, for a value of n, the divider is (2^n), maximum + value of n is 2 for a divider of 4 */ +#define CLKPWR_HCLKDIV_DIV_2POW(n) ((n) & 0x3) + +/********************************************************************** +* clkpwr_pwr_ctrl register definitions +**********************************************************************/ +/* Force HCLK and ARMCLK to run from PERIPH_CLK to save power */ +#define CLKPWR_CTRL_FORCE_PCLK _BIT(10) +/* SDRAM self refresh request */ +#define CLKPWR_SDRAM_SELF_RFSH _BIT(9) +/* Update SDRAM self refresh request */ +#define CLKPWR_UPD_SDRAM_SELF_RFSH _BIT(8) +/* Enable auto exit SDRAM self refresh */ +#define CLKPWR_AUTO_SDRAM_SELF_RFSH _BIT(7) +/* Highcore pin level (when CLKPWR_HIGHCORE_GPIO_EN is set) */ +#define CLKPWR_HIGHCORE_STATE_BIT _BIT(5) +/* SYSCLKEN pin level (when CLKPWR_SYSCLKEN_GPIO_EN is set) */ +#define CLKPWR_SYSCLKEN_STATE_BIT _BIT(4) +/* Enable SYSCLKEN pin as a GPIO bit */ +#define CLKPWR_SYSCLKEN_GPIO_EN _BIT(3) +/* Selects direct run mode (0) or run mode (1) */ +#define CLKPWR_SELECT_RUN_MODE _BIT(2) +/* Enable Highcore pin as a GPIO bit */ +#define CLKPWR_HIGHCORE_GPIO_EN _BIT(1) +/* Enable Highcore pin as a GPIO bit */ +#define CLKPWR_STOP_MODE_CTRL _BIT(0) + +/********************************************************************** +* clkpwr_pll397_ctrl register definitions +**********************************************************************/ +/* Backup PLL397 lock status mask bit */ +#define CLKPWR_PLL397_MSLOCK_STS _BIT(10) +/* PLL397 bypass enable bit */ +#define CLKPWR_PLL397_BYPASS _BIT(9) +/* PLL397 charge pump biases */ +/* Normal charge pump bias */ +#define CLKPWR_PLL397_BIAS_NORM 0x000 +/* -12.5% charge pump bias */ +#define CLKPWR_PLL397_BIAS_N12_5 0x040 +/* -25% charge pump bias */ +#define CLKPWR_PLL397_BIAS_N25 0x080 +/* -37.5% charge pump bias */ +#define CLKPWR_PLL397_BIAS_N37_5 0x0C0 +/* 12.5% charge pump bias */ +#define CLKPWR_PLL397_BIAS_P12_5 0x100 +/* 25% charge pump bias */ +#define CLKPWR_PLL397_BIAS_P25 0x140 +/* 37.5% charge pump bias */ +#define CLKPWR_PLL397_BIAS_P37_5 0x180 +/* 50% charge pump bias */ +#define CLKPWR_PLL397_BIAS_P50 0x1C0 +/* PLL397 charge pump bias mask */ +#define CLKPWR_PLL397_BIAS_MASK 0x1C0 +/* PLL397 enable/disable bit, (0) = enable, (1) = disable */ +#define CLKPWR_SYSCTRL_PLL397_DIS _BIT(1) +/* Read only status mask bit of the PLL397 oscillator lock state, + (0) = PLL397 is not locked, (1) = PLL397 is locked */ +#define CLKPWR_SYSCTRL_PLL397_STS _BIT(0) + +/********************************************************************** +* clkpwr_main_osc_ctrl register definitions +**********************************************************************/ +/* Main oscillator load cap adder, adds 0 to 12.7pF, or 0.1pF per + increment */ +#define CLKPWR_MOSC_ADD_CAP(n) (((n) & 0x7F) << 2) +/* Main oscillator load cap adder bit mask */ +#define CLKPWR_MOSC_CAP_MASK (0x7F << 2) +/* Main oscillator test mode, passes through mode */ +#define CLKPWR_TEST_MODE _BIT(1) +/* Main oscillator disable, power down mode */ +#define CLKPWR_MOSC_DISABLE _BIT(0) + +/********************************************************************** +* clkpwr_sysclk_ctrl register definitions +**********************************************************************/ +/* Number used by the clock switching circuitry to decide how long a + bad phase must be present before clock switching is triggered */ +#define CLKPWR_SYSCTRL_BP_TRIG(n) (((n) & 0x3FF) << 2) +/* Mask for bad phase bits */ +#define CLKPWR_SYSCTRL_BP_MASK (0x3FF << 2) +/* (1) = Use main oscillator, (1) = use PLL397 oscillator */ +#define CLKPWR_SYSCTRL_USEPLL397 _BIT(1) +/* Read only status mask bit of the select oscillator, (0) = main + oscillator, (1) = PLL397 oscillator */ +#define CLKPWR_SYSCTRL_SYSCLKMUX _BIT(0) + +/********************************************************************** +* clkpwr_lcdclk_ctrl register definitions +**********************************************************************/ +/* Muxed pin configuration for TFT display and RGB444 support */ +#define CLKPWR_LCDCTRL_LCDTYPE_TFT12 0x000 +/* Muxed pin configuration for TFT display and RGB565 support */ +#define CLKPWR_LCDCTRL_LCDTYPE_TFT16 0x040 +/* Muxed pin configuration for TFT display and RGB1:555 support */ +#define CLKPWR_LCDCTRL_LCDTYPE_TFT15 0x080 +/* Muxed pin configuration for TFT display and RGB888 support */ +#define CLKPWR_LCDCTRL_LCDTYPE_TFT24 0x0C0 +/* Muxed pin configuration for STN display and 4-bit mono support */ +#define CLKPWR_LCDCTRL_LCDTYPE_STN4M 0x100 +/* Muxed pin configuration for STN display and 8-bit mono or color + support */ +#define CLKPWR_LCDCTRL_LCDTYPE_STN8C 0x140 +/* Muxed pin configuration for DSTN display and 4-bit mono support */ +#define CLKPWR_LCDCTRL_LCDTYPE_DSTN4M 0x180 +/* Muxed pin configuration for DSTN display and 8-bit mono or color + support */ +#define CLKPWR_LCDCTRL_LCDTYPE_DSTN8C 0x1C0 +/* Mask for LCD panel type */ +#define CLKPWR_LCDCTRL_LCDTYPE_MSK 0x01C0 +/* LCD clock disable (0) / enable (1) bit */ +#define CLKPWR_LCDCTRL_CLK_EN 0x020 +/* Macro for setting LCD prescaler, n = 1 to 32 */ +#define CLKPWR_LCDCTRL_SET_PSCALE(n) ((n - 1) & 0x1F) +/* Mask for LCD prescaler */ +#define CLKPWR_LCDCTRL_PSCALE_MSK 0x001F + +/********************************************************************** +* clkpwr_hclkpll_ctrl register definitions +**********************************************************************/ +/* Bit to start (1) or stop (0) the main HCLK PLL */ +#define CLKPWR_HCLKPLL_POWER_UP _BIT(16) +/* Main HCLK PLL CCO bypass control (0) = CCO clock to post divider, + (1) = Bypass CCO and route PLL clock to post divider */ +#define CLKPWR_HCLKPLL_CCO_BYPASS _BIT(15) +/* Main HCLK PLL post divider bypass control (0) = use post divider, + (1) = Bypass post divider */ +#define CLKPWR_HCLKPLL_POSTDIV_BYPASS _BIT(14) +/* Main HCLK PLL feedback divider path control, (0) = feedback + divider clocked by CCO, (1) = feedback divider clocked by FCLKOUT */ +#define CLKPWR_HCLKPLL_FDBK_SEL_FCLK _BIT(13) +/* Main HCLK PLL post divider setting, for a value of n, the divider + is 2^n, maximum value of n is 3 */ +#define CLKPWR_HCLKPLL_POSTDIV_2POW(n) (((n) & 0x3) << 11) +/* Main HCLK PLL pre divider setting, for a value of n, the divider + is (1+n), maximum value of n is 3 */ +#define CLKPWR_HCLKPLL_PREDIV_PLUS1(n) (((n) & 0x3) << 9) +/* Main HCLK PLL feedback setting, for a value of n, the feedback + is (1+n), maximum value of n is 255 */ +#define CLKPWR_HCLKPLL_PLLM(n) (((n) & 0xFF) << 1) +/* Read only status mask bit of the PLL lock state, (0) = PLL is not + locked, (1) = PLL is locked */ +#define CLKPWR_HCLKPLL_PLL_STS _BIT(0) + +/********************************************************************** +* clkpwr_adc_clk_ctrl_1 register definitions +**********************************************************************/ +/* Macro for setting the ADC clock divider when the PERIPH_CLK is + selected, n = 1 to 256, use 0 to disable */ +#define CLKPWR_ADCCTRL1_RTDIV(n) (((n) & 0xFF) << 0) +/* Clock selection bit for ADC, (0) = RTC, (1) = PERIPH_CLK */ +#define CLKPWR_ADCCTRL1_PCLK_SEL _BIT(8) + +/********************************************************************** +* clkpwr_usb_ctrl register definitions +**********************************************************************/ +/* USB slave HCLK clock disable (0) / enable (1) bit */ +#define CLKPWR_USBCTRL_HCLK_EN _BIT(24) +/* USB I2C enable, (0) = automatic USB I2C enable, (1) = disable (by + driving '0' to the OE_TP_N pad */ +#define CLKPWR_USBCTRL_USBI2C_EN _BIT(23) +/* USB_DEV_NEED_CLK enable, (0) = USB_DEV_NEED_CLK not let into clock + switch, (1) = USB_DEV_NEED_CLK let into clock switch */ +#define CLKPWR_USBCTRL_USBDVND_EN _BIT(22) +/* USB_HOST_NEED_CLK enable, (0) = USB_HOST_NEED_CLK not let into clock + switch, (1) = USB_HOST_NEED_CLK let into clock switch */ +#define CLKPWR_USBCTRL_USBHSTND_EN _BIT(21) +/* USB_DAT_VP and USB_SE0_VM pull-up added to pad */ +#define CLKPWR_USBCTRL_PU_ADD (0x0 << 19) +/* USB_DAT_VP and USB_SE0_VM bus keeper mode */ +#define CLKPWR_USBCTRL_BUS_KEEPER (0x1 << 19) +/* USB_DAT_VP and USB_SE0_VM pull-down added to pad */ +#define CLKPWR_USBCTRL_PD_ADD (0x3 << 19) +/* USB (CLKEN2) clock disable (0) / enable (1) bit */ +#define CLKPWR_USBCTRL_CLK_EN2 _BIT(18) +/* USB (CLKEN1) clock disable (0) / enable (1) bit */ +#define CLKPWR_USBCTRL_CLK_EN1 _BIT(17) +/* USB PLL Power up (1) / power down (0) bit */ +#define CLKPWR_USBCTRL_PLL_PWRUP _BIT(16) +/* USB PLL CCO bypass bit, (0) = use post divider, (1) = bypass */ +#define CLKPWR_USBCTRL_CCO_BYPASS _BIT(15) +/* USB PLL direct output bit, (0) = use post divider as PLL output, + (1) = bypass post divider */ +#define CLKPWR_USBCTRL_POSTDIV_BYPASS _BIT(14) +/* USB PLL feedback divider path control, (0) = feedback + divider clocked by CCO, (1) = feedback divider clocked by FCLKOUT */ +#define CLKPWR_USBCTRL_FDBK_SEL_FCLK _BIT(13) +/* USB PLL post divider setting, for a value of n, the divider is 2^n, + maximum value of n is 3 */ +#define CLKPWR_USBCTRL_POSTDIV_2POW(n) (((n) & 0x3) << 11) +/* USB PLL pre divider setting, for a value of n, the divider + is (1+n), maximum value of n is 3 */ +#define CLKPWR_USBCTRL_PREDIV_PLUS1(n) (((n) & 0x3) << 9) +/* USB PLL feedback setting, for a value of n, the feedback + is (1+n), maximum value of n is 255 */ +#define CLKPWR_USBCTRL_FDBK_PLUS1(n) (((n) & 0xFF) << 1) +/* Read only status mask bit of the USB PLL lock state, (0) = PLL is + not locked, (1) = PLL is locked */ +#define CLKPWR_USBCTRL_PLL_STS _BIT(0) + +/********************************************************************** +* clkpwr_sdramclk_ctrl register definitions +**********************************************************************/ +/* SDRAM RAM_CLK fast slew rate control selection bit */ +#define CLKPWR_SDRCLK_FASTSLEW_CLK _BIT(22) +/* SDRAM grouping fast slew rate control selection bit */ +#define CLKPWR_SDRCLK_FASTSLEW _BIT(21) +/* SDRAM data fast slew rate control selection bit */ +#define CLKPWR_SDRCLK_FASTSLEW_DAT _BIT(20) +/* SDRAM/DDR controller reset bit */ +#define CLKPWR_SDRCLK_SW_DDR_RESET _BIT(19) +/* Select HCLK delay calibration value, n = 0 to 31 at .25nS per tick */ +#define CLKPWR_SDRCLK_HCLK_DLY(n) (((n) & 0x1F) << 14) +/* SDRAM/DDR delay circuitry address status bit */ +#define CLKPWR_SDRCLK_DLY_ADDR_STS _BIT(13) +/* Sensitivity factor for DDR SDRAM cal, n = 0 to 7 */ +#define CLKPWR_SDRCLK_SENS_FACT(n) (((n) & 0x7) << 10) +/* Use calibrated settings for DDR SDRAM bit */ +#define CLKPWR_SDRCLK_USE_CAL _BIT(9) +/* Perform a DDR delay calibration bit */ +#define CLKPWR_SDRCLK_DO_CAL _BIT(8) +/* Enable auto DDR cal on RTC tick bit */ +#define CLKPWR_SDRCLK_CAL_ON_RTC _BIT(7) +/* Select DQS input delay value, n = 0 to 31 at .25nS per tick */ +#define CLKPWR_SDRCLK_DQS_DLY(n) (((n) & 0x1F) << 2) +/* Use DDR (1) or SDRAM (0) bit */ +#define CLKPWR_SDRCLK_USE_DDR _BIT(1) +/* SDRAM/DDR clock disable bit */ +#define CLKPWR_SDRCLK_CLK_DIS _BIT(0) + +/********************************************************************** +* clkpwr_ssp_blk_ctrl register definitions +**********************************************************************/ +/* SSP1 RX DMA selection, (0) = SSP1RX not connected/SPI2 connected, + (1) = SSP1RX connected/SPI2 not connected */ +#define CLKPWR_SSPCTRL_DMA_SSP1RX _BIT(5) +/* SSP1 TX DMA selection, (0) = SSP1TX not connected/SPI1 connected, + (1) = SSP1TX connected/SPI1 not connected */ +#define CLKPWR_SSPCTRL_DMA_SSP1TX _BIT(4) +/* SSP0 RX DMA selection, (0) = SSP1RX not connected/SPI2 connected, + (1) = SSP1RX connected/SPI3 not connected */ +#define CLKPWR_SSPCTRL_DMA_SSP0RX _BIT(3) +/* SSP0 TX DMA selection, (0) = SSP1TX not connected/SPI1 connected, + (1) = SSP1TX connected/SPI4 not connected */ +#define CLKPWR_SSPCTRL_DMA_SSP0TX _BIT(2) +/* SSP0 clock disable (0) / enable (1) bit */ +#define CLKPWR_SSPCTRL_SSPCLK1_EN _BIT(1) +/* SSP0 clock disable (0) / enable (1) bit */ +#define CLKPWR_SSPCTRL_SSPCLK0_EN _BIT(0) + +/********************************************************************** +* clkpwr_i2s_clk_ctrl register definitions +**********************************************************************/ +/* I2S1 TX clock mode, (0) = TX clock drives TX timing, (1) = RX clock + drives TX timing */ +#define CLKPWR_I2SCTRL_I2S1_RX_FOR_TX _BIT(6) +/* I2S1 RX clock mode, (0) = RX clock drives RX timing, (1) = TX clock + drives RX timing */ +#define CLKPWR_I2SCTRL_I2S1_TX_FOR_RX _BIT(5) +/* I2S1 DMA muxing, (0) = HS-UAT7 uses DMA, (1) = I2S1 uses DMA */ +#define CLKPWR_I2SCTRL_I2S1_USE_DMA _BIT(4) +/* I2S0 TX clock mode, (0) = TX clock drives TX timing, (1) = RX clock + drives TX timing */ +#define CLKPWR_I2SCTRL_I2S0_RX_FOR_TX _BIT(3) +/* I2S0 RX clock mode, (0) = RX clock drives RX timing, (1) = TX clock + drives RX timing */ +#define CLKPWR_I2SCTRL_I2S0_TX_FOR_RX _BIT(2) +/* I2S1 clock disable (0) / enable (1) bit */ +#define CLKPWR_I2SCTRL_I2SCLK1_EN _BIT(1) +/* I2S0 clock disable (0) / enable (1) bit */ +#define CLKPWR_I2SCTRL_I2SCLK0_EN _BIT(0) + +/********************************************************************** +* clkpwr_ms_ctrl register definitions +**********************************************************************/ +/* Disable SD pins(1) or enable (0) */ +#define CLKPWR_MSCARD_MSDIO_PIN_DIS _BIT(10) +/* MSSDIO pullup enable (1) / disable (0) */ +#define CLKPWR_MSCARD_MSDIO_PU_EN _BIT(9) +/* MSSDIO data 2 and 3 pullup disable (1) / enable (0) */ +#define CLKPWR_MSCARD_MSDIO23_DIS _BIT(8) +/* MSSDIO data 1 pullup disable (1) / enable (0) */ +#define CLKPWR_MSCARD_MSDIO1_DIS _BIT(7) +/* MSSDIO data 0 pullup disable (1) / enable (0) */ +#define CLKPWR_MSCARD_MSDIO0_DIS _BIT(6) +/* SDCard clock disable (0) / enable (1) */ +#define CLKPWR_MSCARD_SDCARD_EN _BIT(5) +/* SDCard clock divider = (ARM_PLL clock / n) Hz, n = 1 to 15, + disabled when n = 0*/ +#define CLKPWR_MSCARD_SDCARD_DIV(n) ((n) & 0xF) + +/********************************************************************** +* clkpwr_macclk_ctrl register definitions +**********************************************************************/ +/* Disables ethernet MAC pins */ +#define CLKPWR_MACCTRL_NO_ENET_PIS 0x00 +/* Ethernet MAC pins setup for MII */ +#define CLKPWR_MACCTRL_USE_MII_PINS 0x08 +/* Ethernet MAC pins setup for RMII */ +#define CLKPWR_MACCTRL_USE_RMII_PINS 0x18 +/* Mask for MAC pins selection */ +#define CLKPWR_MACCTRL_PINS_MSK 0x18 +/* Ethernet MAC DMA clock disable (0) / enable (1) bit */ +#define CLKPWR_MACCTRL_DMACLK_EN _BIT(2) +/* Ethernet MAC MMIO clock disable (0) / enable (1) bit */ +#define CLKPWR_MACCTRL_MMIOCLK_EN _BIT(1) +/* Ethernet MAC host registers clock disable (0) / enable (1) bit */ +#define CLKPWR_MACCTRL_HRCCLK_EN _BIT(0) + +/********************************************************************** +* clkpwr_test_clk_sel register definitions +**********************************************************************/ +/* Route PERIPH_CLK to TEST_CLK1 pin */ +#define CLKPWR_TESTCLK1_SEL_PERCLK (0x0 << 5) +/* Route RTC to TEST_CLK1 pin */ +#define CLKPWR_TESTCLK1_SEL_RTC (0x1 << 5) +/* Route Main oscillator clock to TEST_CLK1 pin */ +#define CLKPWR_TESTCLK1_SEL_MOSC (0x2 << 5) +/* TEST_CLK1 pin signal selection mask */ +#define CLKPWR_TESTCLK1_SEL_MASK (0x3 << 5) +/* TEST_CLK1 output select, (0) = connected to GPO_00, (1) = use + selected test 1 clock */ +#define CLKPWR_TESTCLK_TESTCLK1_EN _BIT(4) +/* Route PERIPH_CLK to TEST_CLK2 pin */ +#define CLKPWR_TESTCLK2_SEL_HCLK (0x0 << 1) +/* Route PERIPH_CLK to TEST_CLK2 pin */ +#define CLKPWR_TESTCLK2_SEL_PERCLK (0x1 << 1) +/* Route USB_CLK to TEST_CLK2 pin */ +#define CLKPWR_TESTCLK2_SEL_USBCLK (0x2 << 1) +/* Route Main oscillator clock to TEST_CLK2 pin */ +#define CLKPWR_TESTCLK2_SEL_MOSC (0x5 << 1) +/* Route PLL397 to TEST_CLK2 pin */ +#define CLKPWR_TESTCLK2_SEL_PLL397 (0x7 << 1) +/* TEST_CLK2 pin signal selection mask */ +#define CLKPWR_TESTCLK2_SEL_MASK (0x7 << 1) +/* TEST_CLK2 output select, (0) = TEST_CLK2 turned off, (1) = use + selected test 2 clock */ +#define CLKPWR_TESTCLK_TESTCLK2_EN _BIT(0) + +/********************************************************************** +* clkpwr_sw_int register definitions +**********************************************************************/ +/* Macro for loading the SW interrupt argument value and generating + and interrupt */ +#define CLKPWR_SW_INT(n) (_BIT(0) | (((n) & 0x7F) << 1)) +/* Macro for reading the SW interrupt argument */ +#define CLKPWR_SW_GET_ARG(n) (((n) & 0xFE) >> 1) + +/********************************************************************** +* clkpwr_i2c_clk_ctrl register definitions +**********************************************************************/ +/* Driver strength for USB_I2C clock and data, (0) = low driver, + (1) = high drive */ +#define CLKPWR_I2CCLK_USBI2CHI_DRIVE _BIT(4) +/* Driver strength for I2C2 clock and data, (0) = low driver, + (1) = high drive */ +#define CLKPWR_I2CCLK_I2C2HI_DRIVE _BIT(3) +/* Driver strength for I2C1 clock and data, (0) = low driver, + (1) = high drive */ +#define CLKPWR_I2CCLK_I2C1HI_DRIVE _BIT(2) +/* Clock enable for I2C2, (0) = disable, (1) = enable */ +#define CLKPWR_I2CCLK_I2C2CLK_EN _BIT(1) +/* Clock enable for I2C1, (0) = disable, (1) = enable */ +#define CLKPWR_I2CCLK_I2C1CLK_EN _BIT(0) + +/********************************************************************** +* clkpwr_key_clk_ctrl register definitions +**********************************************************************/ +/* Key scanner clock disable (0) / enable (1) bit */ +#define CLKPWR_KEYCLKCTRL_CLK_EN 0x1 + +/********************************************************************** +* clkpwr_adc_clk_ctrl register definitions +**********************************************************************/ +/* ADC 32KHz clock disable (0) / enable (1) bit */ +#define CLKPWR_ADC32CLKCTRL_CLK_EN 0x1 + +/********************************************************************** +* clkpwr_pwm_clk_ctrl register definitions +**********************************************************************/ +/* PWM2 clock frequency = CLKIN / n, n = 1 to 15, disabled when + n = 0 */ +#define CLKPWR_PWMCLK_PWM2_DIV(n) (((n) & 0xF) << 8) +/* PWM1 clock frequency = CLKIN / n, n = 1 to 15, disabled when + n = 0 */ +#define CLKPWR_PWMCLK_PWM1_DIV(n) (((n) & 0xF) << 4) +/* Selects PWM2 clock source, (0) = 32KHz clock, (1) = PERIPH_CLK */ +#define CLKPWR_PWMCLK_PWM2SEL_PCLK 0x8 +/* Enables PWM2 clock, (0) = disable, (1) = enable */ +#define CLKPWR_PWMCLK_PWM2CLK_EN 0x4 +/* Selects PWM1 clock source, (0) = 32KHz clock, (1) = PERIPH_CLK */ +#define CLKPWR_PWMCLK_PWM1SEL_PCLK 0x2 +/* Enables PWM1 clock, (0) = disable, (1) = enable */ +#define CLKPWR_PWMCLK_PWM1CLK_EN 0x1 + +/********************************************************************** +* clkpwr_timer_clk_ctrl register definitions +**********************************************************************/ +/* High speed timer clock enable, (0) = disable, (1) = enable */ +#define CLKPWR_PWMCLK_HSTIMER_EN 0x2 +/* Watchdog timer clock enable, (0) = disable, (1) = enable */ +#define CLKPWR_PWMCLK_WDOG_EN 0x1 + +/********************************************************************** +* clkpwr_timers_pwms_clk_ctrl_1 register definitions +**********************************************************************/ +/* Timer 3 clock enable, (0) = disable, (1) = enable */ +#define CLKPWR_TMRPWMCLK_TIMER3_EN 0x20 +/* Timer 2 clock enable, (0) = disable, (1) = enable */ +#define CLKPWR_TMRPWMCLK_TIMER2_EN 0x10 +/* Timer 1 clock enable, (0) = disable, (1) = enable */ +#define CLKPWR_TMRPWMCLK_TIMER1_EN 0x08 +/* Timer 0 clock enable, (0) = disable, (1) = enable */ +#define CLKPWR_TMRPWMCLK_TIMER0_EN 0x04 +/* PWM 4 clock enable, (0) = disable, (1) = enable */ +#define CLKPWR_TMRPWMCLK_PWM4_EN 0x02 +/* PWM 3 clock enable, (0) = disable, (1) = enable */ +#define CLKPWR_TMRPWMCLK_PWM3_EN 0x01 + +/********************************************************************** +* clkpwr_spi_clk_ctrl register definitions +**********************************************************************/ +/* SPI2 DATIO output level is CLKPWR_SPICLK_USE_SPI2 is 0 */ +#define CLKPWR_SPICLK_SET_SPI2DATIO 0x80 +/* SPI2 CLK output level is CLKPWR_SPICLK_USE_SPI2 is 0 */ +#define CLKPWR_SPICLK_SET_SPI2CLK 0x40 +/* SPI2 DATIO and CLK output control, (0) = GPO values in bits 6 and + 7, (1) = controlled by the SPI2 block */ +#define CLKPWR_SPICLK_USE_SPI2 0x20 +/* SPI2 clock enable, (0) = disable, (1) = enable */ +#define CLKPWR_SPICLK_SPI2CLK_EN 0x10 +/* SPI1 DATIO output level is CLKPWR_SPICLK_USE_SPI1 is 0 */ +#define CLKPWR_SPICLK_SET_SPI1DATIO 0x08 +/* SPI1 CLK output level is CLKPWR_SPICLK_USE_SPI1 is 0 */ +#define CLKPWR_SPICLK_SET_SPI1CLK 0x04 +/* SPI1 DATIO and CLK output control, (0) = GPO values in bits 2 and + 3, (1) = controlled by the SPI1 block */ +#define CLKPWR_SPICLK_USE_SPI1 0x02 +/* SPI1 clock enable, (0) = disable, (1) = enable */ +#define CLKPWR_SPICLK_SPI1CLK_EN 0x01 + +/********************************************************************** +* clkpwr_nand_clk_ctrl register definitions +**********************************************************************/ +/* NAND FLASH controller interrupt select, (0) = SLC, (1) = MLC */ +#define CLKPWR_NANDCLK_INTSEL_MLC 0x20 +/* Enable DMA_REQ on NAND_RnB for MLC */ +#define CLKPWR_NANDCLK_DMA_RNB 0x10 +/* Enable DMA_REQ on NAND_INT for MLC */ +#define CLKPWR_NANDCLK_DMA_INT 0x08 +/* NAND FLASH controller select, (0) = MLC, (1) = SLC */ +#define CLKPWR_NANDCLK_SEL_SLC 0x04 +/* NAND FLASH MLC clock enable, (0) = disable, (1) = enable */ +#define CLKPWR_NANDCLK_MLCCLK_EN 0x02 +/* NAND FLASH SLC clock enable, (0) = disable, (1) = enable */ +#define CLKPWR_NANDCLK_SLCCLK_EN 0x01 + +/********************************************************************** +* clkpwr_uart3_clk_ctrl, clkpwr_uart4_clk_ctrl, clkpwr_uart5_clk_ctrl +* and clkpwr_uart6_clk_ctrl register definitions +**********************************************************************/ +/* Macro for loading UART 'Y' divider value */ +#define CLKPWR_UART_Y_DIV(y) ((y) & 0xFF) +/* Macro for loading UART 'X' divider value */ +#define CLKPWR_UART_X_DIV(x) (((x) & 0xFF) << 8) +/* Bit for using HCLK as the UART X/Y divider input, or PERIPH_CLK */ +#define CLKPWR_UART_USE_HCLK _BIT(16) + +/********************************************************************** +* clkpwr_irda_clk_ctrl register definitions +**********************************************************************/ + +/* Macro for loading IRDA 'Y' divider value */ +#define CLKPWR_IRDA_Y_DIV(y) ((y) & 0xFF) +/* Macro for loading IRDA 'X' divider value */ +#define CLKPWR_IRDA_X_DIV(x) (((x) & 0xFF) << 8) + +/********************************************************************** +* clkpwr_uart_clk_ctrl register definitions +**********************************************************************/ +/* UART6 clock disable (0) / enable (1) bit */ +#define CLKPWR_UARTCLKCTRL_UART6_EN _BIT(3) +/* UART5 clock disable (0) / enable (1) bit */ +#define CLKPWR_UARTCLKCTRL_UART5_EN _BIT(2) +/* UART4 clock disable (0) / enable (1) bit */ +#define CLKPWR_UARTCLKCTRL_UART4_EN _BIT(1) +/* UART3 clock disable (0) / enable (1) bit */ +#define CLKPWR_UARTCLKCTRL_UART3_EN _BIT(0) + +/********************************************************************** +* clkpwr_dmaclk_ctrl register definitions +**********************************************************************/ +/* DMA clock disable (0) / enable (1) bit */ +#define CLKPWR_DMACLKCTRL_CLK_EN 0x1 + +/********************************************************************** +* clkpwr_autoclock register definitions +**********************************************************************/ +/* (0) = enable USB autoclock, (1) = always clock */ +#define CLKPWR_AUTOCLK_USB_EN 0x40 +/* (0) = enable IRAM autoclock, (1) = always clock */ +#define CLKPWR_AUTOCLK_IRAM_EN 0x02 +/* (0) = enable IROM autoclock, (1) = always clock */ +#define CLKPWR_AUTOCLK_IROM_EN 0x01 + +#endif /* LPC32XX_CLKPWR_H */ diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_dmac.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_dmac.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_dmac.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_dmac.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,289 @@ +/* + * asm-arm/arch-lpc32xx/lpc32xx_dmac.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 LPC32XX_DMAC_H +#define LPC32XX_DMAC_H + +#ifndef _BIT +#define _BIT(n) (1 << (n)) +#endif + +/********************************************************************** +* DMA register offsets +**********************************************************************/ + +/* DMA controller register structures */ +#define DMA_INT_STAT(x) (x + 0x00) +#define DMA_INT_TC_STAT(x) (x + 0x04) +#define DMA_INT_TC_CLEAR(x) (x + 0x08) +#define DMA_INT_ERR_STAT(x) (x + 0x0C) +#define DMA_INT_ERR_CLEAR(x) (x + 0x10) +#define DMA_RAW_TC_STAT(x) (x + 0x14) +#define DMA_RAW_ERR_STAT(x) (x + 0x18) +#define DMA_CH_ENABLE(x) (x + 0x1C) +#define DMA_SW_BURST_REQ(x) (x + 0x20) +#define DMA_SW_SINGLE_REQ(x) (x + 0x24) +#define DMA_SW_LAST_BURST_REQ(x) (x + 0x28) +#define DMA_SW_LAST_SINGLE_REQ(x) (x + 0x2C) +#define DMA_CONFIG(x) (x + 0x30) +#define DMA_SYNC(x) (x + 0x34) + +/* DMA controller channel register structure */ +#define DMA_CH_OFFS(c) ((c * 0x20) + 0x100) +#define DMACH_SRC_ADDR(x, c) (x + DMA_CH_OFFS(c) + 0x00) +#define DMACH_DEST_ADDR(x, c) (x + DMA_CH_OFFS(c) + 0x04) +#define DMACH_LLI(x, c) (x + DMA_CH_OFFS(c) + 0x08) +#define DMACH_CONTROL(x, c) (x + DMA_CH_OFFS(c) + 0x0C) +#define DMACH_CONFIG_CH(x, c) (x + DMA_CH_OFFS(c) + 0x10) + +/* DMA linked list structure */ +#define DMA_LL_SRC(x) (x + 0x0) +#define DMA_LL_DEST(x) (x + 0x4) +#define DMA_LL_NEXT_LLI(x) (x + 0x8) +#define DMA_LL_NEXT_CTRL(x) (x + 0xC) + +#define DMA_LL_SIZE 16 + +/********************************************************************** +* int_stat, int_tc_stat, int_tc_clear, int_err_stat, raw_tc_stat, +* raw_err_stat, and chan_enable register definitions +**********************************************************************/ +/* Macro for determining a bit position for a channel */ +#define DMAC_GET_CHAN_POS(chan) (0x1 << ((chan) & 0x7)) + +/********************************************************************** +* sw_burst_req, sw_single_req, sw_last_burst_req, sw_last_single_req, +* and sync register definitions +**********************************************************************/ +/* Peripheral DMA bit position for I2S0 DMA0 */ +#define DMA_PER_I2S0_DMA0 _BIT(0) + +/* Peripheral DMA bit position for NAND FLASH (same as 12) */ +#define DMA_PER_NAND1 _BIT(1) + +/* Peripheral DMA bit position for I2S1 DMA0 */ +#define DMA_PER_I2S1_DMA0 _BIT(2) + +/* Peripheral DMA bit position for SPI2 (RX and TX) */ +#define DMA_PER_SPI2_TXRX _BIT(3) + +/* Peripheral DMA bit position for SSP1 (RX) */ +#define DMA_PER_SSP1_RX _BIT(3) + +/* Peripheral DMA bit position for SD card */ +#define DMA_PER_SDCARD _BIT(4) + +/* Peripheral DMA bit position for HSUART1 TX */ +#define DMA_PER_HSUART1_TX _BIT(5) + +/* Peripheral DMA bit position for HSUART1 RX */ +#define DMA_PER_HSUART1_RX _BIT(6) + +/* Peripheral DMA bit position for HSUART2 TX */ +#define DMA_PER_HSUART2_TX _BIT(7) + +/* Peripheral DMA bit position for HSUART2 RX */ +#define DMA_PER_HSUART2_RX _BIT(8) + +/* Peripheral DMA bit position for HSUART7 TX */ +#define DMA_PER_HSUART7_TX _BIT(9) + +/* Peripheral DMA bit position for HSUART7 RX */ +#define DMA_PER_HSUART7_RX _BIT(10) + +/* Peripheral DMA bit position for I2S1 DMA1 */ +#define DMA_PER_I2S1_DMA1 _BIT(10) + +/* Peripheral DMA bit position for SPI1 (RX and TX) */ +#define DMA_PER_SPI1_TXRX _BIT(11) + +/* Peripheral DMA bit position for SSP1 (TX) */ +#define DMA_PER_SSP1_TX _BIT(11) + +/* Peripheral DMA bit position for NAND FLASH (same as 1) */ +#define DMA_PER_NAND2 _BIT(12) + +/* Peripheral DMA bit position for I2S0 DMA1 */ +#define DMA_PER_I2S0_DMA1 _BIT(13) + +/* Peripheral DMA bit position for SSP0 (RX) */ +#define DMA_PER_SSP0_RX _BIT(14) + +/* Peripheral DMA bit position for SSP0 (TX) */ +#define DMA_PER_SSP0_TX _BIT(15) + +/********************************************************************** +* config register definitions +**********************************************************************/ +/* Bit for enabling big endian mode on AHB 1 */ +#define DMAC_BIG_ENDIAN_AHB1 _BIT(2) + +/* Bit for enabling big endian mode on AHB 0 */ +#define DMAC_BIG_ENDIAN_AHB0 _BIT(1) + +/* Bit for enabling the DMA controller */ +#define DMAC_CTRL_ENABLE _BIT(0) + +/********************************************************************** +* lli register definitions +**********************************************************************/ +/* Bit for selecting AHB0 (0) or AHB1 (1) */ +#define DMAC_CHAN_LLI_SEL_AHB1 _BIT(0) + +/********************************************************************** +* control register definitions +**********************************************************************/ +/* Bit for enabling a channel terminal count interrupt */ +#define DMAC_CHAN_INT_TC_EN _BIT(31) + +/* Bit for indicating address is cacheable */ +#define DMAC_CHAN_PROT3 _BIT(30) + +/* Bit for indicating address is bufferable */ +#define DMAC_CHAN_PROT2 _BIT(29) + +/* Bit for indicating address is privelaged mode (1) or user + mode (0) */ +#define DMAC_CHAN_PROT1 _BIT(28) + +/* Bit for enabling automatic destination increment */ +#define DMAC_CHAN_DEST_AUTOINC _BIT(27) + +/* Bit for enabling automatic source increment */ +#define DMAC_CHAN_SRC_AUTOINC _BIT(26) + +/* Bit for using AHB1 master for destination transfer */ +#define DMAC_CHAN_DEST_AHB1 _BIT(25) + +/* Bit for using AHB1 master for source transfer */ +#define DMAC_CHAN_SRC_AHB1 _BIT(24) + +/* Destination data width selection defines */ +#define DMAC_CHAN_DEST_WIDTH_8 0x0 +#define DMAC_CHAN_DEST_WIDTH_16 _BIT(21) +#define DMAC_CHAN_DEST_WIDTH_32 _BIT(22) + +/* Source data width selection defines */ +#define DMAC_CHAN_SRC_WIDTH_8 0x0 +#define DMAC_CHAN_SRC_WIDTH_16 _BIT(18) +#define DMAC_CHAN_SRC_WIDTH_32 _BIT(19) + +/* Destination data burst size defines (in transfer width) */ +#define DMAC_CHAN_DEST_BURST_1 0 +#define DMAC_CHAN_DEST_BURST_4 _BIT(15) +#define DMAC_CHAN_DEST_BURST_8 _BIT(16) +#define DMAC_CHAN_DEST_BURST_16 (_BIT(16) | _BIT(15)) +#define DMAC_CHAN_DEST_BURST_32 _BIT(17) +#define DMAC_CHAN_DEST_BURST_64 (_BIT(17) | _BIT(15)) +#define DMAC_CHAN_DEST_BURST_128 (_BIT(17) | _BIT(16)) +#define DMAC_CHAN_DEST_BURST_256 (_BIT(17) | _BIT(16) | _BIT(15)) + +/* Macro for direct loading of destination burst size field */ +#define DMAC_CHAN_DEST_BURST_LOAD(n) (((n) & 0x7) << 15) + +/* Source data burst size defines (in transfer width) */ +#define DMAC_CHAN_SRC_BURST_1 0 +#define DMAC_CHAN_SRC_BURST_4 _BIT(12) +#define DMAC_CHAN_SRC_BURST_8 _BIT(13) +#define DMAC_CHAN_SRC_BURST_16 (_BIT(13) | _BIT(12)) +#define DMAC_CHAN_SRC_BURST_32 _BIT(14) +#define DMAC_CHAN_SRC_BURST_64 (_BIT(14) | _BIT(12)) +#define DMAC_CHAN_SRC_BURST_128 (_BIT(14) | _BIT(13)) +#define DMAC_CHAN_SRC_BURST_256 (_BIT(14) | _BIT(13) | _BIT(12)) + +/* Macro for direct loading of source burst size field */ +#define DMAC_CHAN_SRC_BURST_LOAD(n) (((n) & 0x7) << 12) + +/* Macro for loading transfer size */ +#define DMAC_CHAN_TRANSFER_SIZE(n) ((n) & 0xFFF) + +/********************************************************************** +* config_ch register definitions +**********************************************************************/ +/* Bit for halting a DMA transfer */ +#define DMAC_CHAN_HALT _BIT(18) + +/* Bit for checking active status of the DMA channel */ +#define DMAC_CHAN_ACTIVE _BIT(17) + +/* Bit for enabling locked transfers */ +#define DMAC_CHAN_LOCK _BIT(16) + +/* Terminal count interrupt mask bit */ +#define DMAC_CHAN_ITC _BIT(15) + +/* Interrupt error mask bit */ +#define DMAC_CHAN_IE _BIT(14) + +/* Defines for flow control with DMA as the controller */ +#define DMAC_CHAN_FLOW_D_M2M (0x0 << 11) +#define DMAC_CHAN_FLOW_D_M2P (0x1 << 11) +#define DMAC_CHAN_FLOW_D_P2M (0x2 << 11) +#define DMAC_CHAN_FLOW_D_SP2DP (0x3 << 11) + +/* Defines for flow control with destination peripheral as the + controller */ +#define DMAC_CHAN_FLOW_DP_SP2DP (0x4 << 11) + +/* Defines for flow control with peripheral as the controller */ +#define DMAC_CHAN_FLOW_P_M2P (0x5 << 11) +#define DMAC_CHAN_FLOW_P_P2M (0x6 << 11) + +/* Defines for flow control with source peripheral as the + controller */ +#define DMAC_CHAN_FLOW_SP_SP2DP (0x7 << 11) + +/* Macro for loading destination peripheral */ +#define DMAC_DEST_PERIP(n) (((n) & 0x1F) << 6) + +/* Macro for loading source peripheral */ +#define DMAC_SRC_PERIP(n) (((n) & 0x1F) << 1) + +/* Channel enable bit */ +#define DMAC_CHAN_ENABLE _BIT(0) + +/********************************************************************** +* config_ch register definitions (source and destination +* peripheral ID numbers). These can be used with the DMAC_DEST_PERIP +* and DMAC_SRC_PERIP macros. +**********************************************************************/ +#define DMA_PERID_I2S0_DMA0 0 +#define DMA_PERID_NAND1 1 +#define DMA_PERID_I2S1_DMA0 2 +#define DMA_PERID_SPI2_TXRX 3 +#define DMA_PERID_SSP1_RX 3 +#define DMA_PERID_SDCARD 4 +#define DMA_PERID_HSUART1_TX 5 +#define DMA_PERID_HSUART1_RX 6 +#define DMA_PERID_HSUART2_TX 7 +#define DMA_PERID_HSUART2_RX 8 +#define DMA_PERID_HSUART7_TX 9 +#define DMA_PERID_HSUART7_RX 10 +#define DMA_PERID_I2S1_DMA1 10 +#define DMA_PERID_SPI1_TXRX 11 +#define DMA_PERID_SSP1_TX 11 +#define DMA_PERID_NAND2 12 +#define DMA_PERID_I2S0_DMA1 13 +#define DMA_PERID_SSP0_RX 14 +#define DMA_PERID_SSP0_TX 15 + +#endif /* LPC32XX_DMAC_H */ diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_gpio.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_gpio.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_gpio.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_gpio.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,223 @@ +/* + * asm-arm/arch-lpc32xx/lpc32xx_gpio.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 LPC32XX_GPIO_H +#define LPC32XX_GPIO_H + +#define _BIT(n) (1 << (n)) + +/*********************************************************************** +* GPIO Module Register offsets +**********************************************************************/ + +#define GPIO_P3_INP_STATE(x) (x + 0x000) +#define GPIO_P3_OUTP_SET(x) (x + 0x004) +#define GPIO_P3_OUTP_CLR(x) (x + 0x008) +#define GPIO_P3_OUTP_STATE(x) (x + 0x00C) +#define GPIO_P2_DIR_SET(x) (x + 0x010) +#define GPIO_P2_DIR_CLR(x) (x + 0x014) +#define GPIO_P2_DIR_STATE(x) (x + 0x018) +#define GPIO_P2_INP_STATE(x) (x + 0x01C) +#define GPIO_P2_OUTP_SET(x) (x + 0x020) +#define GPIO_P2_OUTP_CLR(x) (x + 0x024) +#define GPIO_P2_MUX_SET(x) (x + 0x028) +#define GPIO_P2_MUX_CLR(x) (x + 0x02C) +#define GPIO_P2_MUX_STATE(x) (x + 0x030) +#define GPIO_P0_INP_STATE(x) (x + 0x040) +#define GPIO_P0_OUTP_SET(x) (x + 0x044) +#define GPIO_P0_OUTP_CLR(x) (x + 0x048) +#define GPIO_P0_OUTP_STATE(x) (x + 0x04C) +#define GPIO_P0_DIR_SET(x) (x + 0x050) +#define GPIO_P0_DIR_CLR(x) (x + 0x054) +#define GPIO_P0_DIR_STATE(x) (x + 0x058) +#define GPIO_P1_INP_STATE(x) (x + 0x060) +#define GPIO_P1_OUTP_SET(x) (x + 0x064) +#define GPIO_P1_OUTP_CLR(x) (x + 0x068) +#define GPIO_P1_OUTP_STATE(x) (x + 0x06C) +#define GPIO_P1_DIR_SET(x) (x + 0x070) +#define GPIO_P1_DIR_CLR(x) (x + 0x074) +#define GPIO_P1_DIR_STATE(x) (x + 0x078) +#define GPIO_P_MUX_SET(x) (x + 0x100) +#define GPIO_P_MUX_CLR(x) (x + 0x104) +#define GPIO_P_MUX_STATE(x) (x + 0x108) +#define GPIO_P3_MUX_SET(x) (x + 0x110) +#define GPIO_P3_MUX_CLR(x) (x + 0x114) +#define GPIO_P3_MUX_STATE(x) (x + 0x118) +#define GPIO_P0_MUX_SET(x) (x + 0x120) +#define GPIO_P0_MUX_CLR(x) (x + 0x124) +#define GPIO_P0_MUX_STATE(x) (x + 0x128) +#define GPIO_P1_MUX_SET(x) (x + 0x130) +#define GPIO_P1_MUX_CLR(x) (x + 0x134) +#define GPIO_P1_MUX_STATE(x) (x + 0x138) + +/* For direction registers, a '1' is an output */ +#define GPIO_DIR_OUT 0x1 + +/*********************************************************************** +* Input Pin State Register defines +**********************************************************************/ +/* Input state of GPI_pin. Where pin = 0-9 */ +#define INP_STATE_GPI_00 _BIT(0) +#define INP_STATE_GPI_01 _BIT(1) +#define INP_STATE_GPI_02 _BIT(2) +#define INP_STATE_GPI_03 _BIT(3) +#define INP_STATE_GPI_04 _BIT(4) +#define INP_STATE_GPI_05 _BIT(5) +#define INP_STATE_GPI_06 _BIT(6) +#define INP_STATE_GPI_07 _BIT(7) +#define INP_STATE_GPI_08 _BIT(8) +#define INP_STATE_GPI_09 _BIT(9) +#define INP_STATE_GPIO_00 _BIT(10) +#define INP_STATE_GPIO_01 _BIT(11) +#define INP_STATE_GPIO_02 _BIT(12) +#define INP_STATE_GPIO_03 _BIT(13) +#define INP_STATE_GPIO_04 _BIT(14) +#define INP_STATE_U1_RX _BIT(15) +#define INP_STATE_U2_HCTS _BIT(16) +#define INP_STATE_U2_RX _BIT(17) +#define INP_STATE_U3_RX _BIT(18) +#define INP_STATE_GPI_19_U4RX _BIT(19) +#define INP_STATE_U5_RX _BIT(20) +#define INP_STATE_U6_IRRX _BIT(21) +#define INP_STATE_U7_HCTS _BIT(22) +#define INP_STATE_U7_RX _BIT(23) +#define INP_STATE_GPIO_05 _BIT(24) +#define INP_STATE_SPI1_DATIN _BIT(25) +#define INP_STATE_SPI2_DATIN _BIT(27) +#define INP_STATE_GPI_28_U3RI _BIT(28) + +/*********************************************************************** +* p3_outp_set, p3_outp_clr, and p3_outp_state register defines +**********************************************************************/ +/* Following macro is used to determine bit position for GPO pin in +* P3_OUTP_SET, P3_OUTP_CLR & P3_OUTP_STATE registers. +* Where pin = {0-23} +*/ +#define OUTP_STATE_GPO(pin) _BIT((pin)) + +/* Following macro is used to determine bit position for GPIO pin in +* PIO_OUTP_SET, P3_OUTP_CLR & P3_OUTP_STATE registers. +* Where pin = {0-5} +*/ +#define OUTP_STATE_GPIO(pin) _BIT(((pin) + 25)) + +/*********************************************************************** +* GPIO Direction Register defines +**********************************************************************/ +/* Following macro is used to determine bit position for GPIO pin in +* P2_DIR_SET, P2_DIR_STATE & P2_DIR_CLR registers. +* Where pin = {0-5} +*/ +#define PIO_DIR_GPIO(pin) _BIT(((pin) + 25)) + +/* Following macro is used to determine bit position for RAM_D pin in +* P2_DIR_SET, P2_DIR_CLR, P2_DIR_STATE, P2_INP_STATE, +* P2_OUTP_SET, & P2_OUTP_CLR. +* Where pin = {19-31} +*/ +#define PIO_SDRAM_DIR_PIN(pin) _BIT(((pin) - 19)) + +/* Macro for GPIO direction muxed with the high 16 bits of the SDRAM + data related bit locations (when configured as a GPIO) */ +#define PIO_SDRAM_PIN_ALL 0x00001FFF + +/*********************************************************************** +* p_mux_set, p_mux_clr, p_mux_state register defines +**********************************************************************/ +/* Muxed PIO#0 pin state defines */ +#define P_I2STXSDA1_MAT31 _BIT(2) +#define P_I2STXCLK1_MAT30 _BIT(3) +#define P_I2STXWS1_CAP30 _BIT(4) +#define P_SPI2DATAIO_MOSI1 _BIT(5) +#define P_SPI2DATAIN_MISO1 _BIT(6) +#define P_SPI2CLK_SCK1 _BIT(8) +#define P_SPI1DATAIO_SSP0_MOSI _BIT(9) +#define P_SPI1DATAIN_SSP0_MISO _BIT(10) +#define P_SPI1CLK_SCK0 _BIT(12) +#define P_MAT21_PWM36 _BIT(13) +#define P_MAT20_PWM35 _BIT(14) +#define P_U7TX_MAT11 _BIT(15) +#define P_MAT03_PWM34 _BIT(17) +#define P_MAT02_PWM33 _BIT(18) +#define P_MAT01_PWM32 _BIT(19) +#define P_MAT00_PWM31 _BIT(20) + +/*********************************************************************** +* p0_mux_set, p0_mux_clr, p0_mux_state register defines +**********************************************************************/ + +/* Following macro is used to determine bit position for a P0 GPIO pin + used with the p0_xxx registers for pins P0_0 to P0_7*/ +#define OUTP_STATE_GPIO_P0(pin) _BIT((pin)) + +/* P0 pin mux defines (0 = GPIO, 1 = alternate function) */ +#define P0_GPOP0_I2SRXCLK1 _BIT(0) +#define P0_GPOP1_I2SRXWS1 _BIT(1) +#define P0_GPOP2_I2SRXSDA0 _BIT(2) +#define P0_GPOP3_I2SRXCLK0 _BIT(3) +#define P0_GPOP4_I2SRXWS0 _BIT(4) +#define P0_GPOP5_I2STXSDA0 _BIT(5) +#define P0_GPOP6_I2STXCLK0 _BIT(6) +#define P0_GPOP7_I2STXWS0 _BIT(7) +#define P0_ALL 0xFF + +/*********************************************************************** +* p1_mux_set, p1_mux_clr, p1_mux_state register defines +**********************************************************************/ + +/* Following macro is used to determine bit position for a P1 GPIO pin + used with the p1_xxx registers for pins P1_0 to P1_23*/ +#define OUTP_STATE_GPIO_P1(pin) _BIT((pin)) + +/* Mask for all GPIO P1 bits */ +#define P1_ALL 0x00FFFFFF + +/* Macro pointing to GPIO registers */ +#define GPIO ((GPIO_REGS_T *)(GPIO_BASE)) + +/*********************************************************************** +* p2_mux_set, p2_mux_clr, p2_mux_state register defines +**********************************************************************/ +/* Muxed PIO#2 pin state defines */ +#define P2_GPIO05_SSEL0 _BIT(5) +#define P2_GPIO04_SSEL1 _BIT(4) +#define P2_SDRAMD19D31_GPIO _BIT(3) +#define P2_GPO21_U4TX _BIT(2) +#define P2_GPIO03_KEYROW7 _BIT(1) +#define P2_GPIO02_KEYROW6 _BIT(0) + +/*********************************************************************** +* p3_mux_set, p3_mux_clr, p3_mux_state register defines +**********************************************************************/ +/* Muxed PIO#3 pin states, first column is '0' state, second is '1' */ +#define P3_GPO2_MAT10 _BIT(2) +#define P3_GPO6_PWM43 _BIT(6) +#define P3_GPO8_PWM42 _BIT(8) +#define P3_GPO9_PWM41 _BIT(9) +#define P3_GPO10_PWM36 _BIT(10) +#define P3_GPO12_PWM35 _BIT(12) +#define P3_GPO13_PWM34 _BIT(13) +#define P3_GPO15_PWM33 _BIT(15) +#define P3_GPO16_PWM32 _BIT(16) +#define P3_GPO18_PWM31 _BIT(18) + +#endif /* LPC32XX_GPIO_H */ diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_hsuart.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_hsuart.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_hsuart.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_hsuart.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,99 @@ +/* + * asm-arm/arch-lpc32xx/lpc32xx_clkpwr.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 LPC32XX_HSUART_H +#define LPC32XX_HSUART_H + +#define _BIT(n) (1 << (n)) +#define _SBF(f,v) (((v)) << (f)) + +/********************************************************************** +* High speed UART register offsets +**********************************************************************/ + +#define HSUART_FIFO(x) (x + 0x00) +#define HSUART_LEVEL(x) (x + 0x04) +#define HSUART_IIR(x) (x + 0x08) +#define HSUART_CTRL(x) (x + 0x0C) +#define HSUART_RATE(x) (x + 0x10) + +/********************************************************************** +* high speed UART receiver FIFO register definitions +**********************************************************************/ +#define HSU_BREAK_DATA _BIT(10) /* break condition indicator*/ +#define HSU_ERROR_DATA _BIT(9) /* framing error indicator */ +#define HSU_RX_EMPTY _BIT(8) /* Rx FIFO empty status */ + +/********************************************************************** +* high speed UART level register definitions +**********************************************************************/ +#define HSU_TX_LEV(n) ((n>>8) & 0xFF) +#define HSU_RX_LEV(n) ((n) & 0xFF) + +/********************************************************************** +* high speed UART interrupt identification register definitions +**********************************************************************/ +#define HSU_TX_INT_SET _BIT(6) /* set the Tx int flag */ +#define HSU_RX_OE_INT _BIT(5) /* overrun int flag */ +#define HSU_BRK_INT _BIT(4) /* break int flag */ +#define HSU_FE_INT _BIT(3) /* framing error flag */ +#define HSU_RX_TIMEOUT_INT _BIT(2) /* Rx timeout int flag */ +#define HSU_RX_TRIG_INT _BIT(1) /* Rx FIFO trig level ind */ +#define HSU_TX_INT _BIT(0) /* Tx interrupt flag */ + +/********************************************************************** +* high speed UART control register definitions +**********************************************************************/ +#define HSU_HRTS_INV _BIT(21) /* HRTS invert ctrl */ +#define HSU_HRTS_TRIG(n) (_SBF(19,(n&0x3))) /* HRTS trig level */ +#define HSU_HRTS_TRIG_8B 0 /* HRTS trig lev 8B */ +#define HSU_HRTS_TRIG_16B _BIT(19) /* HRTS trig lev 16B */ +#define HSU_HRTS_TRIG_32B _BIT(20) /* HRTS trig lev 32B */ +#define HSU_HRTS_TRIG_48B _SBF(19,0x3) /* HRTS trig lev 48B */ +#define HSU_HRTS_EN _BIT(18) /* HRTS enable ctrl */ +#define HSU_TMO_CONFIG(n) ((n) & _SBF(16,0x3))/* tout intconfig */ +#define HSU_TMO_DISABLED 0 /* Rx tmo disabled */ +#define HSU_TMO_INACT_4B _BIT(16) /* tmo after 4 bits */ +#define HSU_TMO_INACT_8B _BIT(17) /* tmo after 8 bits */ +#define HSU_TMO_INACT_16B _SBF(16,0x3) /* tmo after 16 bits */ +#define HSU_HCTS_INV _BIT(15) /* HCTS inverted */ +#define HSU_HCTS_EN _BIT(14) /* Tx flow control */ +#define HSU_OFFSET(n) _SBF(9,n) /* 1st samplingpoint */ +#define HSU_BREAK _BIT(8) /* break control */ +#define HSU_ERR_INT_EN _BIT(7) /* HSUART err int en */ +#define HSU_RX_INT_EN _BIT(6) /* HSUART Rx int en */ +#define HSU_TX_INT_EN _BIT(5) /* HSUART Tx int en */ +#define HSU_RX_TRIG(n) ((n) & _SBF(2,0x7)) /* Rx FIFO trig lev */ +#define HSU_RX_TL1B _SBF(2,0x0) /* Rx FIFO trig 1B */ +#define HSU_RX_TL4B _SBF(2,0x1) /* Rx FIFO trig 4B */ +#define HSU_RX_TL8B _SBF(2,0x2) /* Rx FIFO trig 8B */ +#define HSU_RX_TL16B _SBF(2,0x3) /* Rx FIFO trig 16B */ +#define HSU_RX_TL32B _SBF(2,0x4) /* Rx FIFO trig 32B */ +#define HSU_RX_TL48B _SBF(2,0x5) /* Rx FIFO trig 48B */ +#define HSU_TX_TRIG(n) ((n) & _SBF(0,0x3)) /* Tx FIFO trig lev */ +#define HSU_TX_TLEMPTY _SBF(0,0x0) /* Tx FIFO trig empty */ +#define HSU_TX_TL0B _SBF(0,0x0) /* Tx FIFO trig empty */ +#define HSU_TX_TL4B _SBF(0,0x1) /* Tx FIFO trig 4B */ +#define HSU_TX_TL8B _SBF(0,0x2) /* Tx FIFO trig 8B */ +#define HSU_TX_TL16B _SBF(0,0x3) /* Tx FIFO trig 16B */ + +#endif /* LPC32XX_HSUART_H */ diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_i2c.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_i2c.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_i2c.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_i2c.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,100 @@ +/* + * asm-arm/arch-lpc32xx/lpc32xx_i2c.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 LPC32XX_I2C_H +#define LPC32XX_I2C_H + +#define _BIT(n) (1 << (n)) + +/********************************************************************** +* I2C controller register offsets +**********************************************************************/ + +#define I2C_TXRX(x) (x + 0x000) +#define I2C_STAT(x) (x + 0x004) +#define I2C_CTRL(x) (x + 0x008) +#define I2C_CLK_HI(x) (x + 0x00C) +#define I2C_CLK_LO(x) (x + 0x010) +#define I2C_ADR(x) (x + 0x014) +#define I2C_RXFL(x) (x + 0x018) +#define I2C_TXFL(x) (x + 0x01C) +#define I2C_RXB(x) (x + 0x020) +#define I2C_TXB(x) (x + 0x024) +#define I2C_STX(x) (x + 0x028) +#define I2C_STXFL(x) (x + 0x02C) + +/********************************************************************** +* i2c_txrx register definitions +**********************************************************************/ +#define I2C_START _BIT(8) /* generate a START before this B*/ +#define I2C_STOP _BIT(9) /* generate a STOP after this B */ + +/********************************************************************** +* i2c_stat register definitions +**********************************************************************/ +#define I2C_TDI _BIT(0) /* Transaction Done Interrupt */ +#define I2C_AFI _BIT(1) /* Arbitration Failure Interrupt */ +#define I2C_NAI _BIT(2) /* No Acknowledge Interrupt */ +#define I2C_DRMI _BIT(3) /* Master Data Request Interrupt */ +#define I2C_DRSI _BIT(4) /* Slave Data Request Interrupt */ +#define I2C_ACTIVE _BIT(5) /* Busy bus indicator */ +#define I2C_SCL _BIT(6) /* The current SCL signal value */ +#define I2C_SDA _BIT(7) /* The current SDA signal value */ +#define I2C_RFF _BIT(8) /* Receive FIFO Full */ +#define I2C_RFE _BIT(9) /* Receive FIFO Empty */ +#define I2C_TFF _BIT(10) /* Transmit FIFO Full */ +#define I2C_TFE _BIT(11) /* Transmit FIFO Empty */ +#define I2C_TFFS _BIT(12) /* Slave Transmit FIFO Full */ +#define I2C_TFES _BIT(13) /* Slave Transmit FIFO Empty */ + +/********************************************************************** +* i2c_ctrl register definitions +**********************************************************************/ +#define I2C_TDIE _BIT(0) /* Transaction Done Int Enable */ +#define I2C_AFIE _BIT(1) /* Arbitration Failure Int Ena */ +#define I2C_NAIE _BIT(2) /* No Acknowledge Int Enable */ +#define I2C_DRMIE _BIT(3) /* Master Data Request Int Ena */ +#define I2C_DRSIE _BIT(4) /* Slave Data Request Int Ena */ +#define I2C_RFFIE _BIT(5) /* Receive FIFO Full Int Ena */ +#define I2C_RFDAIE _BIT(6) /* Rcv Data Available Int Ena */ +#define I2C_TFFIE _BIT(7) /* Trnsmt FIFO Not Full Int Ena */ +#define I2C_RESET _BIT(8) /* Soft Reset */ +#define I2C_SEVEN _BIT(9) /* Seven-bit slave address */ +#define I2C_TFFSIE _BIT(10) /* Slave Trnsmt FIFO Not Full IE */ + +/********************************************************************** +* i2c channel select +**********************************************************************/ + +/* Macro pointing to I2C controller registers */ +#define I2C1 ((I2C_REGS_T *)(I2C1_BASE)) +#define I2C2 ((I2C_REGS_T *)(I2C2_BASE)) + +#define I2C_RX_BUFFER_SIZE 4 +#define I2C_TX_BUFFER_SIZE 4 +#define I2C_STX_BUFFER_SIZE 4 + +#ifdef __cplusplus +} +#endif + +#endif /* LPC32XX_I2C_H */ diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_i2s.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_i2s.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_i2s.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_i2s.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,159 @@ +/* + * asm-arm/arch-lpc32xx/lpc32xx_i2c.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 LPC32XX_I2S_H +#define LPC32XX_I2S_H + +#define _BIT(n) (1 << (n)) +#define _SBF(f,v) (((v)) << (f)) + +/********************************************************************** +* I2S controller register offsets +**********************************************************************/ + +#define I2S_DAO(x) (x + 0x00) +#define I2S_DAI(x) (x + 0x04) +#define I2S_TX_FIFO(x) (x + 0x08) +#define I2S_RX_FIFO(x) (x + 0x0C) +#define I2S_STAT(x) (x + 0x10) +#define I2S_DMA0(x) (x + 0x14) +#define I2S_DMA1(x) (x + 0x18) +#define I2S_IRQ(x) (x + 0x1C) +#define I2S_TX_RATE(x) (x + 0x20) +#define I2S_RX_RATE(x) (x + 0x24) + +/********************************************************************** +* i2s_daO i2s_dai register definitions +**********************************************************************/ +#define I2S_WW8 _SBF(0,0) /* Word width is 8bit*/ +#define I2S_WW16 _SBF(0,1) /* Word width is 16bit*/ +#define I2S_WW32 _SBF(0,3) /* Word width is 32bit*/ +#define I2S_MONO _BIT(2) /* Mono */ +#define I2S_STOP _BIT(3) /* Stop, diables the access to FIFO, + mutes the channel */ +#define I2S_RESET _BIT(4) /* Reset the channel */ +#define I2S_WS_SEL _BIT(5) /* Channel Master(0) or slave(1) + mode select*/ +#define I2S_WS_HP(s) _SBF(6,s) /* Word select half period - 1 */ + +#define I2S_MUTE _BIT(15) /* Mute the channel, + Transmit channel only */ + +#define I2S_WW32_HP 0x1f /* Word select half period for 32bit + word width */ +#define I2S_WW16_HP 0x0f /* Word select half period for 16bit + word width */ +#define I2S_WW8_HP 0x7 /* Word select half period for 8bit + word width */ + +#define WSMASK_HP 0X7FC /* Mask for WS half period bits */ + +/********************************************************************** +* i2s_tx_fifo register definitions +**********************************************************************/ +#define I2S_FIFO_TX_WRITE(d) (d) + +/********************************************************************** +* i2s_rx_fifo register definitions +**********************************************************************/ +#define I2S_FIFO_RX_WRITE(d) (d) + +/********************************************************************** +* i2s_stat register definitions +**********************************************************************/ +#define I2S_IRQ_STAT _BIT(0) +#define I2S_DMA0_REQ _BIT(1) +#define I2S_DMA1_REQ _BIT(2) + +#define I2S_RX_STATE_MASK 0x0000ff00 +#define I2S_TX_STATE_MASK 0x00ff0000 + +/********************************************************************** +* i2s_dma0 Configuration register definitions +**********************************************************************/ +#define I2S_DMA0_RX_EN _BIT(0) /* Enable RX DMA1*/ +#define I2S_DMA0_TX_EN _BIT(1) /* Enable TX DMA1*/ +#define I2S_DMA0_RX_DEPTH(s) _SBF(8,s) /* Set the level for DMA1 + RX Request */ +#define I2S_DMA0_TX_DEPTH(s) _SBF(16,s) /* Set the level for DMA1 + TX Request */ + +/********************************************************************** +* i2s_dma1 Configuration register definitions +**********************************************************************/ +#define I2S_DMA1_RX_EN _BIT(0) /* Enable RX DMA1*/ +#define I2S_DMA1_TX_EN _BIT(1) /* Enable TX DMA1*/ +#define I2S_DMA1_RX_DEPTH(s) _SBF(8,s) /* Set the level for DMA1 + RX Request */ +#define I2S_DMA1_TX_DEPTH(s) _SBF(16,s) /* Set the level for DMA1 + TX Request */ + +/********************************************************************** +* i2s_irq register definitions +**********************************************************************/ +#define I2S_RX_IRQ_EN _BIT(0) /* Enable RX IRQ*/ +#define I2S_TX_IRQ_EN _BIT(1) /* Enable TX IRQ*/ +#define I2S_IRQ_RX_DEPTH(s) _SBF(8,s) /* valid values ar 0 to 7 */ +#define I2S_IRQ_TX_DEPTH(s) _SBF(16,s) /* valid values ar 0 to 7 */ + +/********************************************************************** +* define audio rates for i2s_tx_rate/i2s_rx_rate register definitions +**********************************************************************/ + +#define A96KHZ104MHZ8BIT 0x7ed // 7, 237 +#define A48KHZ104MHZ8BIT 0x3cb // 3, 203 +#define A44KHZ104MHZ8BIT 0x14a // 1, 74 +#define A32KHZ104MHZ8BIT 0x5fe // 5, 254 +#define A22KHZ104MHZ8BIT 0x194 // 1, 148 +#define A16KHZ104MHZ8BIT 0x1cb // 1, 203 + +#define A96KHZ104MHZ16BIT 0xeed // 14, 237 +#define A48KHZ104MHZ16BIT 0x7ED // 7, 237 +#define A44KHZ104MHZ16BIT 0x6dd // 6, 221 +#define A32KHZ104MHZ16BIT 0x5fe // 5, 254 +#define A22KHZ104MHZ16BIT 0x14a // 1, 74 +#define A16KHZ104MHZ16BIT 0x2cb // 2, 203 + +#define A96KHZ104MHZ32BIT 0x1ced// 28, 237 +#define A48KHZ104MHZ32BIT 0xeed // 14, 237 +#define A44KHZ104MHZ32BIT 0xdf0 // 13, 240 +#define A32KHZ104MHZ32BIT 0x57f // 5, 127 +#define A22KHZ104MHZ32BIT 0x125 // 1, 37 +#define A16KHZ104MHZ32BIT 0x5fe // 5, 254 + +/********************************************************************** +* i2s_tx_rate register definitions +**********************************************************************/ +#define I2S_SET_TX_RATE(d) (d) + +/********************************************************************** +* i2s_rx_rate register definitions +**********************************************************************/ +#define I2S_SET_RX_RATE(d) (d) + +/********************************************************************** +* i2s channel select +**********************************************************************/ +#define I2S_CH0 0 +#define I2S_CH1 1 + +#endif /* LPC32XX_I2S_H */ diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_kscan.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_kscan.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_kscan.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_kscan.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,85 @@ +/* + * asm-arm/arch-lpc32xx/lpc32xx_kscan.h + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 LPC32XX_KSCAN_H +#define LPC32XX_KSCAN_H + +#define _BIT(n) (1 << (n)) + +/********************************************************************** +* Key scanner register offsets +**********************************************************************/ + +#define KS_DEB(x) (x + 0x00) +#define KS_STATE_COND(x) (x + 0x04) +#define KS_IRQ(x) (x + 0x08) +#define KS_SCAN_CTL(x) (x + 0x0C) +#define KS_FAST_TST(x) (x + 0x10) +#define KS_MATRIX_DIM(x) (x + 0x14) +#define KS_DATA(x) (x + 0x40) + +/********************************************************************** +* ks_deb register definitions +**********************************************************************/ +/* Keypad debouncing register, number of equal matrix values read, + n = 0 to 255 passes */ +#define KSCAN_DEB_NUM_DEB_PASS(n) ((n) & 0xFF) + +/********************************************************************** +* ks_state_cond register definitions +**********************************************************************/ +/* Keypad in the idle state */ +#define KSCAN_SCOND_IN_IDLE 0x0 +/* Keypad in the scan-once state */ +#define KSCAN_SCOND_IN_SCANONCE 0x1 +/* Keypad in the IRQ generation state */ +#define KSCAN_SCOND_IN_IRQGEN 0x2 +/* Keypad in the IRQ scan-matrix state */ +#define KSCAN_SCOND_IN_SCAN_MATRIX 0x3 + +/********************************************************************** +* ks_irq register definitions +**********************************************************************/ +/* Interrupt pending flag, write to clear */ +#define KSCAN_IRQ_PENDING_CLR 0x1 + +/********************************************************************** +* ks_scan_ctl register definitions +**********************************************************************/ +/* Time in clocks between each scan state in matrix mode, n = 1 to + 255, use 0 for scan always */ +#define KSCAN_SCTRL_SCAN_DELAY(n) ((n) & 0xFF) + +/********************************************************************** +* ks_fast_tst register definitions +**********************************************************************/ +/* Force scan-once state */ +#define KSCAN_FTST_FORCESCANONCE 0x1 +/* Select keypad scanner clock, 0 = PERIPH_CLK, 1 = 32K clock */ +#define KSCAN_FTST_USE32K_CLK 0x2 + +/********************************************************************** +* ks_matrix_dim register definitions +**********************************************************************/ +/* Matrix dimension selection clock, n = 1 to 8 for a 1x1 to 8x8 + matrix */ +#define KSCAN_MSEL_SELECT(n) ((n) & 0xF) + +#endif /* LPC32XX_KSCAN_H */ diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_mac.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_mac.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_mac.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_mac.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,616 @@ +/* + * asm-arm/arch-lpc32xx/lpc32xx_mac.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 LPC32XX_MAC_H +#define LPC32XX_MAC_H + +#define _BIT(n) (1 << (n)) + +/********************************************************************** +* Ethernet MAC controller Register offsets +**********************************************************************/ + +/* MAC registers */ +#define ENET_MAC1(x) (x + 0x000) +#define ENET_MAC2(x) (x + 0x004) +#define ENET_IPGT(x) (x + 0x008) +#define ENET_IPGR(x) (x + 0x00C) +#define ENET_CLRT(x) (x + 0x010) +#define ENET_MAXF(x) (x + 0x014) +#define ENET_SUPP(x) (x + 0x018) +#define ENET_TEST(x) (x + 0x01C) +#define ENET_MCFG(x) (x + 0x020) +#define ENET_MCMD(x) (x + 0x024) +#define ENET_MADR(x) (x + 0x028) +#define ENET_MWTD(x) (x + 0x02C) +#define ENET_MRDD(x) (x + 0x030) +#define ENET_MIND(x) (x + 0x034) +#define ENET_SA0(x) (x + 0x040) +#define ENET_SA1(x) (x + 0x044) +#define ENET_SA2(x) (x + 0x048) + +/* Control registers */ +#define ENET_COMMAND(x) (x + 0x100) +#define ENET_STATUS(x) (x + 0x104) +#define ENET_RXDESCRIPTOR(x) (x + 0x108) +#define ENET_RXSTATUS(x) (x + 0x10C) +#define ENET_RXDESCRIPTORNUMBER(x) (x + 0x110) +#define ENET_RXPRODUCEINDEX(x) (x + 0x114) +#define ENET_RXCONSUMEINDEX(x) (x + 0x118) +#define ENET_TXDESCRIPTOR(x) (x + 0x11C) +#define ENET_TXSTATUS(x) (x + 0x120) +#define ENET_TXDESCRIPTORNUMBER(x) (x + 0x124) +#define ENET_TXPRODUCEINDEX(x) (x + 0x128) +#define ENET_TXCONSUMEINDEX(x) (x + 0x12C) +#define ENET_TSV0(x) (x + 0x158) +#define ENET_TSV1(x) (x + 0x15C) +#define ENET_RSV(x) (x + 0x160) +#define ENET_FLOWCONTROLCOUNTER(x) (x + 0x170) +#define ENET_FLOWCONTROLSTATUS(x) (x + 0x174) + +/* RX filter registers */ +#define ENET_RXFILTER_CTRL(x) (x + 0x200) +#define ENET_RXFILTERWOLSTATUS(x) (x + 0x204) +#define ENET_RXFILTERWOLCLEAR(x) (x + 0x208) +#define ENET_HASHFILTERL(x) (x + 0x210) +#define ENET_HASHFILTERH(x) (x + 0x214) + +/* RX filter registers */ +#define ENET_INTSTATUS(x) (x + 0xFE0) +#define ENET_INTENABLE(x) (x + 0xFE4) +#define ENET_INTCLEAR(x) (x + 0xFE8) +#define ENET_INTSET(x) (x + 0xFEC) +#define ENET_POWERDOWN(x) (x + 0xFF4) + +/* Structure of a TX/RX descriptor */ +struct txrx_desc_t +{ + volatile u32 packet; + volatile u32 control; +}; + +/* Structure of a RX status entry */ +struct rx_status_t +{ + volatile u32 statusinfo; + volatile u32 statushashcrc; +}; + +/********************************************************************** +* mac1 register definitions +**********************************************************************/ +/* Set this to allow receive frames to be received. Internally the + MAC synchronize this control bit to the incoming receive stream */ +#define MAC1_RECV_ENABLE _BIT(0) +/* When enabled (set to ’1’), the MAC will pass all frames regardless + of type (normal vs. Control). When disabled, the MAC does not pass + valid Control frames */ +#define MAC1_PASS_ALL_RX_FRAMES _BIT(1) +/* When enabled (set to ’1’), the MAC acts upon received PAUSE Flow + Control frames. When disabled, received PAUSE Flow Control frames + are ignored */ +#define MAC1_RX_FLOW_CONTROL _BIT(2) +/* When enabled (set to ’1’), PAUSE Flow Control frames are allowed + to be transmitted. When disabled, Flow Control frames are blocked */ +#define MAC1_TX_FLOW_CONTROL _BIT(3) +/* Setting this bit will cause the MAC Transmit interface to be + looped back to the MAC Receive interface. Clearing this bit + results in normal operation */ +#define MAC1_LOOPBACK _BIT(4) +/* Setting this bit will put the Transmit Function logic in reset */ +#define MAC1_RESET_TX _BIT(8) +/* Setting this bit resets the MAC Control Sublayer / Transmit logic. + The MCS logic implements flow control */ +#define MAC1_RESET_MCS_TX _BIT(9) +/* Setting this bit will put the Ethernet receive logic in reset */ +#define MAC1_RESET_RX _BIT(10) +/* Setting this bit resets the MAC Control Sublayer / Receive logic. + The MCS logic implements flow control */ +#define MAC1_RESET_MCS_RX _BIT(11) +/* Setting this bit will cause a reset to the random number generator + within the Transmit Function */ +#define MAC1_SIMULATION_RESET _BIT(14) +/* Setting this bit will put all modules within the MAC in reset + except the Host Interface */ +#define MAC1_SOFT_RESET _BIT(15) + +/********************************************************************** +* mac2 register definitions +**********************************************************************/ +/* When enabled (set to ’1’), the MAC operates in Full-Duplex mode. + When disabled the MAC operates in Half-Duplex mode */ +#define MAC2_FULL_DUPLEX _BIT(0) +/* When enabled (set to ’1’), both transmit and receive frame lengths + are compared to the Length/Type field. If the Length/Type field + represents a length then the check is performed. Mismatches are + reported in the StatusInfo word for each received frame */ +#define MAC2_FRAME_LENGTH_CHECKING _BIT(1) +/* When enabled (set to ’1’), frames of any length are transmitted + and received */ +#define MAC2_HUGH_LENGTH_CHECKING _BIT(2) +/* This bit determines the number of bytes, if any, of proprietary + header information that exist on the front of IEEE 802.3 frames. + When 1, four bytes of header (ignored by the CRC function) are + added. When 0, there is no proprietary header */ +#define MAC2_DELAYED_CRC _BIT(3) +/* Set this bit to append a CRC to every frame whether padding was + required or not. Must be set if PAD/CRC ENABLE is set. Clear this + bit if frames presented to the MAC contain a CRC */ +#define MAC2_CRC_ENABLE _BIT(4) +/* Set this bit to have the MAC pad all short frames. Clear this bit + if frames presented to the MAC have a valid length. This bit is used + in conjunction with AUTO PAD ENABLE and VLAN PAD ENABLE */ +#define MAC2_PAD_CRC_ENABLE _BIT(5) +/* Set this bit to cause the MAC to pad all short frames to 64 bytes + and append a valid CRC. Note: This bit is ignored if + MAC2_PAD_CRC_ENABLE is cleared */ +#define MAC2_VLAN_PAD_ENABLE _BIT(6) +/* Set this bit to cause the MAC to automatically detect the type of + frame, either tagged or un-tagged, by comparing the two octets + following the source address with 0x8100 (VLAN Protocol ID) and + pad accordingly. Table 14–273 - Pad Operation provides a description + of the pad function based on the configuration of this register. + Note: This bit is ignored if PAD / CRC ENABLE is cleared */ +#define MAC2_AUTO_DETECT_PAD_ENABLE _BIT(7) +/* When enabled (set to ’1’), the MAC will verify the content of the + preamble to ensure it contains 0x55 and is error-free. A packet + with an incorrect preamble is discarded. When disabled, no preamble + checking is performed */ +#define MAC2_PURE_PREAMBLE_ENFORCEMENT _BIT(8) +/* When enabled (set to ’1’), the MAC only allows receive packets + which contain preamble fields less than 12 bytes in length. When + disabled, the MAC allows any length preamble as per the Standard */ +#define MAC2_LONG_PREAMBLE_ENFORCEMENT _BIT(9) +/* When enabled (set to ’1’), the MAC will immediately retransmit + following a collision rather than using the Binary Exponential + Backoff algorithm as specified in the Standard */ +#define MAC2_NO_BACKOFF _BIT(12) +/* When enabled (set to ’1’), after the MAC incidentally causes a + collision during back pressure, it will immediately retransmit + without backoff, reducing the chance of further collisions and + ensuring transmit packets get sent */ +#define MAC2_BACK_PRESSURE _BIT(13) +/* When enabled (set to ’1’) the MAC will defer to carrier indefinitely + as per the Standard. When disabled, the MAC will abort when the + excessive deferral limit is reached */ +#define MAC2_EXCESS_DEFER _BIT(14) + +/********************************************************************** +* ipgt register definitions +**********************************************************************/ +/* This is a programmable field representing the nibble time offset + of the minimum possible period between the end of any transmitted + packet to the beginning of the next. In Full-Duplex mode, the + register value should be the desired period in nibble times minus 3. + In Half-Duplex mode, the register value should be the desired + period in nibble times minus 6. In Full-Duplex the recommended + setting is 0x15 (21d), which represents the minimum IPG of 960 ns + (in 100 Mbps mode) or 9.6 ?s (in 10 Mbps mode). In Half-Duplex the + recommended setting is 0x12 (18d), which also represents the minimum + IPG of 960 ns (in 100 Mbps mode) or 9.6 ?s (in 10 Mbps mode) */ +#define IPGT_LOAD(n) ((n) & 0x7F) + +/********************************************************************** +* ipgr register definitions +**********************************************************************/ +/* This is a programmable field representing the Non-Back-to-Back + Inter-Packet-Gap. The recommended value is 0x12 (18d), which + represents the minimum IPG of 960 ns (in 100 Mbps mode) or 9.6 ?s + (in 10 Mbps mode) */ +#define IPGR_LOAD_PART2(n) ((n) & 0x7F) +/* This is a programmable field representing the optional carrierSense + window referenced in IEEE 802.3/4.2.3.2.1 'Carrier Deference'. If + carrier is detected during the timing of IPGR1, the MAC defers to + carrier. If, however, carrier becomes active after IPGR1, the MAC + continues timing IPGR2 and transmits, knowingly causing a collision, + thus ensuring fair access to medium. Its range of values is 0x0 to + IPGR2. The recommended value is 0xC (12d) */ +#define IPGR_LOAD_PART1(n) (((n) & 0x7F) << 8) + +/********************************************************************** +* clrt register definitions +**********************************************************************/ +/* This is a programmable field specifying the number of + retransmission attempts following a collision before aborting the + packet due to excessive collisions. The Standard specifies the + attemptLimit to be 0xF (15d). See IEEE 802.3/4.2.3.2.5. */ +#define CLRT_LOAD_RETRY_MAX(n) ((n) & 0xF) +/* This is a programmable field representing the slot time or + collision window during which collisions occur in properly + configured networks. The default value of 0x37 (55d) represents a + 56 byte window following the preamble and SFD. */ +#define CLRT_LOAD_COLLISION_WINDOW(n) (((n) & 0x3F) << 8) + +/********************************************************************** +* maxf register definitions +**********************************************************************/ +/* This field resets to the value 0x0600, which represents a maximum + receive frame of 1536 octets. An untagged maximum size Ethernet + frame is 1518 octets. A tagged frame adds four octets for a total + of 1522 octets. If a shorter maximum length restriction is desired, + program this 16 bit field. */ +#define MAXF_LOAD_MAX_FRAME_LEN(n) ((n) & 0xFFFF) + +/********************************************************************** +* supp register definitions +**********************************************************************/ +/* This bit configures the Reduced MII logic for the current operating + speed. When set, 100 Mbps mode is selected. When cleared, 10 Mbps + mode is selected */ +#define SUPP_SPEED _BIT(8) +/* Reset Reduced MII Logic */ +#define SUPP_RESET_RMII _BIT(11) + +/********************************************************************** +* test register definitions +**********************************************************************/ +/* This bit reduces the effective PAUSE quanta from 64 byte-times to + 1 byte-time. */ +#define TEST_SHORTCUT_PAUSE_QUANTA _BIT(0) +/* This bit causes the MAC Control sublayer to inhibit transmissions, + just as if a PAUSE Receive Control frame with a nonzero pause time + parameter was received. */ +#define TEST_PAUSE _BIT(1) +/* Setting this bit will cause the MAC to assert backpressure on the + link. Backpressure causes preamble to be transmitted, raising + carrier sense. A transmit packet from the system will be sent + during backpressure. */ +#define TEST_BACKPRESSURE _BIT(2) + +/********************************************************************** +* mcfg register definitions +**********************************************************************/ +/* Set this bit to cause the MII Management hardware to perform read + cycles across a range of PHYs. When set, the MII Management + hardware will perform read cycles from address 1 through the value + set in PHY ADDRESS[4:0]. Clear this bit to allow continuous reads + of the same PHY. */ +#define MCFG_SCAN_INCREMENT _BIT(0) +/* Set this bit to cause the MII Management hardware to perform + read/write cycles without the 32 bit preamble field. Clear this bit + to cause normal cycles to be performed. Some PHYs support + suppressed preamble. */ +#define MCFG_SUPPRESS_PREAMBLE _BIT(1) +/* This field is used by the clock divide logic in creating the MII + Management Clock (MDC) which IEEE 802.3u defines to be no faster + than 2.5 MHz. Some PHYs support clock rates up to 12.5 MHz, + however. Refer to Table 14–280 below for the definition of values + for this field. */ +#define MCFG_CLOCK_SELECT(n) (((n) & 0x7) << 2) +/* MCFG_CLOCK_SELECT macro load values */ +#define MCFG_CLOCK_HOST_DIV_4 0 +#define MCFG_CLOCK_HOST_DIV_6 2 +#define MCFG_CLOCK_HOST_DIV_8 3 +#define MCFG_CLOCK_HOST_DIV_10 4 +#define MCFG_CLOCK_HOST_DIV_14 5 +#define MCFG_CLOCK_HOST_DIV_20 6 +#define MCFG_CLOCK_HOST_DIV_28 7 +/* This bit resets the MII Management hardware */ +#define MCFG_RESET_MII_MGMT _BIT(15) + +/********************************************************************** +* mcmd register definitions +**********************************************************************/ +/* This bit causes the MII Management hardware to perform a single + Read cycle. The Read data is returned in Register MRDD (MII Mgmt + Read Data). */ +#define MCMD_READ _BIT(0) +/* This bit causes the MII Management hardware to perform Read cycles + continuously. This is useful for monitoring Link Fail for example */ +#define MCMD_SCAN _BIT(1) + +/********************************************************************** +* madr register definitions +**********************************************************************/ +/* This field represents the 5 bit Register Address field of Mgmt + cycles. Up to 32 registers can be accessed. */ +#define MADR_REGISTER_ADDRESS(n) ((n) & 0x1F) +/* This field represents the 5 bit PHY Address field of Mgmt + cycles. Up to 31 PHYs can be addressed (0 is reserved). */ +#define MADR_PHY_0ADDRESS(n) (((n) & 0x1F) << 8) + +/********************************************************************** +* mwtd register definitions +**********************************************************************/ +/* When written, an MII Mgmt write cycle is performed using the 16 bit + data and the pre-configured PHY and Register addresses from the + MII Mgmt Address register (MADR). */ +#define MWDT_WRITE(n) ((n) & 0xFFFF) + +/********************************************************************** +* mrdd register definitions +**********************************************************************/ +/* Read mask for MUU read */ +#define MRDD_READ_MASK 0xFFFF + +/********************************************************************** +* mind register definitions +**********************************************************************/ +/* When ’1’ is returned - indicates MII Mgmt is currently performing + an MII Mgmt Read or Write cycle. */ +#define MIND_BUSY _BIT(0) +/* When ’1’ is returned - indicates a scan operation (continuous MII + Mgmt Read cycles) is in progress. */ +#define MIND_SCANNING _BIT(1) +/* When ’1’ is returned - indicates MII Mgmt Read cycle has not + completed and the Read Data is not yet valid. */ +#define MIND_NOT_VALID _BIT(2) +/* When ’1’ is returned - indicates that an MII Mgmt link fail has + occurred.*/ +#define MIND_MII_LINK_FAIL _BIT(3) + +/********************************************************************** +* command register definitions +**********************************************************************/ +/* Enable receive */ +#define COMMAND_RXENABLE _BIT(0) +/* Enable transmit */ +#define COMMAND_TXENABLE _BIT(1) +/* When a ’1’ is written, all datapaths and the host registers are + reset. The MAC needs to be reset separately. */ +#define COMMAND_REG_RESET _BIT(3) +/* When a ’1’ is written, the transmit datapath is reset. */ +#define COMMAND_TXRESET _BIT(4) +/* When a ’1’ is written, the receive datapath is reset. */ +#define COMMAND_RXRESET _BIT(5) +/* When set to ’1’, passes runt frames smaller than 64 bytes to + memory unless they have a CRC error. If ’0’ runt frames are + filtered out. */ +#define COMMAND_PASSRUNTFRAME _BIT(6) +/* When set to ’1’, disables receive filtering i.e. all frames + received are written to memory. */ +#define COMMAND_PASSRXFILTER _BIT(7) +/* Enable IEEE 802.3 / clause 31 flow control sending pause + frames in full duplex and continuous preamble in half duplex. */ +#define COMMAND_TXFLOWCONTROL _BIT(8) +/* When set to ’1’, RMII mode is selected; if ’0’, MII mode is + selected. */ +#define COMMAND_RMII _BIT(9) +/* When set to ’1’, indicates full duplex operation. */ +#define COMMAND_FULLDUPLEX _BIT(10) + +/********************************************************************** +* status register definitions +**********************************************************************/ +/* If 1, the receive channel is active. If 0, the receive channel is + inactive. */ +#define STATUS_RXACTIVE _BIT(0) +/* If 1, the transmit channel is active. If 0, the transmit channel is + inactive. */ +#define STATUS_TXACTIVE _BIT(1) + +/********************************************************************** +* tsv0 register definitions +**********************************************************************/ +/* The attached CRC in the packet did not match the internally + generated CRC. */ +#define TSV0_CRC_ERROR _BIT(0) +/* Indicates the frame length field does not match the actual + number of data items and is not a type field. */ +#define TSV0_LENGTH_CHECK_ERROR _BIT(1) +/* Indicates that frame type/length field was larger tha 1500 bytes. */ +#define TSV0_LENGTH_OUT_OF_RANGE _BIT(2) +/* Transmission of packet was completed. */ +#define TSV0_DONE _BIT(3) +/* Packet’s destination was a multicast address. */ +#define TSV0_MULTICAST _BIT(4) +/* Packet’s destination was a broadcast address. */ +#define TSV0_BROADCAST _BIT(5) +/* Packet was deferred for at least one attempt, but less than + an excessive defer. */ +#define TSV0_PACKET_DEFER _BIT(6) +/* Packet was deferred in excess of 6071 nibble times in + 100 Mbps or 24287 bit times in 10 Mbps mode. */ +#define TSV0_ESCESSIVE_DEFER _BIT(7) +/* Packet was aborted due to exceeding of maximum allowed + number of collisions. */ +#define TSV0_ESCESSIVE_COLLISION _BIT(8) +/* Collision occurred beyond collision window, 512 bit times. */ +#define TSV0_LATE_COLLISION _BIT(9) +/* Byte count in frame was greater than can be represented + in the transmit byte count field in TSV1. */ +#define TSV0_GIANT _BIT(10) +/* Host side caused buffer underrun. */ +#define TSV0_UNDERRUN _BIT(11) +/* Macro: The total number of bytes transferred including + collided attempts. */ +#define TSV0_TOTAL_BYTES(n) (((n) >> 12) & 0xFFFF) +/* The frame was a control frame. */ +#define TSV0_CONTROL_FRAME _BIT(28) +/* The frame was a control frame with a valid PAUSE opcode. */ +#define TSV0_PAUSE _BIT(29) +/* Carrier-sense method backpressure was previously applied. */ +#define TSV0_BACKPRESSURE _BIT(30) +/* Frame’s length/type field contained 0x8100 which is the + VLAN protocol identifier. */ +#define TSV0_VLAN _BIT(31) + +/********************************************************************** +* tsv1 register definitions +**********************************************************************/ +/* Macro: The total number of bytes in the frame, not counting the + collided bytes. */ +#define TSV1_TRANSMIT_BYTE_COUNT(n) ((n) & 0xFFFF) +/* Macro: Number of collisions the current packet incurred during + transmission attempts. The maximum number of collisions + (16) cannot be represented. */ +#define TSV1_COLLISION_COUNT(n) (((n) >> 16) & 0xF) + +/********************************************************************** +* rsv register definitions +**********************************************************************/ +/* Macro: Indicates length of received frame. */ +#define RSV_RECEIVED_BYTE_COUNT(n) ((n) & 0xFFFF) +/* Indicates that a packet was dropped. */ +#define RSV_RXDV_EVENT_IGNORED _BIT(16) +/* Indicates that the last receive event seen was not long + enough to be a valid packet. */ +#define RSV_RXDV_EVENT_PREVIOUSLY_SEEN _BIT(17) +/* Indicates that at some time since the last receive statistics, + a carrier event was detected. */ +#define RSV_CARRIER_EVNT_PREVIOUS_SEEN _BIT(18) +/* Indicates that MII data does not represent a valid receive + code. */ +#define RSV_RECEIVE_CODE_VIOLATION _BIT(19) +/* The attached CRC in the packet did not match the internally + generated CRC. */ +#define RSV_CRC_ERROR _BIT(20) +/* Indicates the frame length field does not match the actual + number of data items and is not a type field. */ +#define RSV_LENGTH_CHECK_ERROR _BIT(21) +/* Indicates that frame type/length field was larger than 1518 bytes */ +#define RSV_LENGTH_OUT_OF_RANGE _BIT(22) +/* The packet had valid CRC and no symbol errors. */ +#define RSV_RECEIVE_OK _BIT(23) +/* The packet destination was a multicast address. */ +#define RSV_MULTICAST _BIT(24) +/* The packet destination was a boardcase address. */ +#define RSV_BROADCAST _BIT(25) +/* Indicates that after the end of packet another 1-7 bits were + received. A single nibble, called dribble nibble, is formed + but not sent out. */ +#define RSV_DRIBBLE_NIBBLE _BIT(26) +/* The frame was a control frame. */ +#define RSV_CONTROL_FRAME _BIT(27) +/* The frame was a control frame with a valid PAUSE opcode. */ +#define RSV_PAUSE _BIT(28) +/* The current frame was recognized as a Control Frame but + contains an unknown opcode. */ +#define RSV_UNSUPPORTED_OPCODE _BIT(29) +/* Frame’s length/type field contained 0x8100 which is the + VLAN protocol identifier. */ +#define RSV_VLAN _BIT(30) + +/********************************************************************** +* flowcontrolcounter register definitions +**********************************************************************/ +/* Macro: In full duplex mode the MirrorCounter specifies the number + of cycles before re-issuing the Pause control frame. */ +#define FCCR_MIRRORCOUNTER(n) ((n) & 0xFFFF) +/* Macro: In full-duplex mode the PauseTimer specifies the value + that is inserted into the pause timer field of a pause flow + control frame. In half duplex mode the PauseTimer + specifies the number of backpressure cycles. */ +#define FCCR_PAUSETIMER(n) (((n) >> 16) & 0xFFFF) + +/********************************************************************** +* flowcontrolstatus register definitions +**********************************************************************/ +/* Macro: In full duplex mode this register represents the current + value of the datapath’s mirror counter which counts up to + the value specified by the MirrorCounter field in the + FlowControlCounter register. In half duplex mode the + register counts until it reaches the value of the PauseTimer + bits in the FlowControlCounter register. */ +#define FCCR_MIRRORCOUNTERCURRENT(n) ((n) & 0xFFFF) + +/********************************************************************** +* rxfliterctrl, rxfilterwolstatus, and rxfilterwolclear shared +* register definitions +**********************************************************************/ +/* Unicast frame control */ +#define RXFLTRW_ACCEPTUNICAST _BIT(0) +/* Broadcase frame control. */ +#define RXFLTRW_ACCEPTUBROADCAST _BIT(1) +/* Multicast frame control */ +#define RXFLTRW_ACCEPTUMULTICAST _BIT(2) +/* Imperfect unicast frame control */ +#define RXFLTRW_ACCEPTUNICASTHASH _BIT(3) +/* Imperfect multicast frame control */ +#define RXFLTRW_ACCEPTUMULTICASTHASH _BIT(4) +/* Perfect frame control */ +#define RXFLTRW_ACCEPTPERFECT _BIT(5) + +/********************************************************************** +* rxfliterctrl register definitions +**********************************************************************/ +/* When set to ’1’, the result of the magic packet filter will + generate a WoL interrupt when there is a match. */ +#define RXFLTRWSTS_MAGICPACKETENWOL _BIT(12) +/* When set to ’1’, the result of the perfect address + matching filter and the imperfect hash filter will + generate a WoL interrupt when there is a match. */ +#define RXFLTRWSTS_RXFILTERENWOL _BIT(13) + +/********************************************************************** +* rxfilterwolstatus register definitions +**********************************************************************/ +/* When the value is ’1’, the receive filter caused WoL. */ +#define RXFLTRWSTS_RXFILTERWOL _BIT(7) +/* When the value is ’1’, the magic packet filter caused WoL. */ +#define RXFLTRWSTS_MAGICPACKETWOL _BIT(8) + +/********************************************************************** +* rxfilterwolclear register definitions +**********************************************************************/ +/* When a ’1’ is written to one of these bits (7 and/or 8), + the corresponding status bit in the rxfilterwolstatus + register is cleared. */ +#define RXFLTRWCLR_RXFILTERWOL RXFLTRWSTS_RXFILTERWOL +#define RXFLTRWCLR_MAGICPACKETWOL RXFLTRWSTS_MAGICPACKETWOL + +/********************************************************************** +* intstatus, intenable, intclear, and Intset shared register +* definitions +**********************************************************************/ +/* Interrupt trigger on receive buffer overrun or descriptor underrun + situations. */ +#define MACINT_RXOVERRUNINTEN _BIT(0) +/* Enable for interrupt trigger on receive errors. */ +#define MACINT_RXERRORONINT _BIT(1) +/* Enable for interrupt triggered when all receive descriptors have + been processed i.e. on the transition to the situation where + ProduceIndex == ConsumeIndex. */ +#define MACINT_RXFINISHEDINTEN _BIT(2) +/* Enable for interrupt triggered when a receive descriptor has + been processed while the Interrupt bit in the Control field of the + descriptor was set. */ +#define MACINT_RXDONEINTEN _BIT(3) +/* Enable for interrupt trigger on transmit buffer or descriptor + underrun situations. */ +#define MACINT_TXUNDERRUNINTEN _BIT(4) +/* Enable for interrupt trigger on transmit errors. */ +#define MACINT_TXERRORINTEN _BIT(5) +/* Enable for interrupt triggered when all transmit descriptors + have been processed i.e. on the transition to the situation + where ProduceIndex == ConsumeIndex. */ +#define MACINT_TXFINISHEDINTEN _BIT(6) +/* Enable for interrupt triggered when a descriptor has been + transmitted while the Interrupt bit in the Control field of the + descriptor was set. */ +#define MACINT_TXDONEINTEN _BIT(7) +/* Enable for interrupt triggered by the SoftInt bit in the IntStatus + register, caused by software writing a 1 to the SoftIntSet bit in + the IntSet register. */ +#define MACINT_SOFTINTEN _BIT(12) +/* Enable for interrupt triggered by a Wakeup event detected by + the receive filter. */ +#define MACINT_WAKEUPINTEN _BIT(13) + +/********************************************************************** +* powerdown register definitions +**********************************************************************/ +/* If true, all AHB accesses will return a read/write error, + except accesses to the PowerDown register. */ +#define POWERDOWN_MACAHB _BIT(31) + +#endif /* LPC32XX_MAC_H */ diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_rtc.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_rtc.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_rtc.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_rtc.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,75 @@ +/* + * asm-arm/arch-lpc32xx/lpc32xx_rtc.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 LPC32XX_RTC_H +#define LPC32XX_RTC_H + +#define _BIT(n) (1 << (n)) + +/********************************************************************** +* Clock and Power control register offsets +**********************************************************************/ + +#define RTC_UCOUNT(x) (x + 0x00) +#define RTC_DCOUNT(x) (x + 0x04) +#define RTC_MATCH0(x) (x + 0x08) +#define RTC_MATCH1(x) (x + 0x0C) +#define RTC_CTRL(x) (x + 0x10) +#define RTC_INTSTAT(x) (x + 0x14) +#define RTC_KEY(x) (x + 0x18) +#define RTC_SRAM(x, y) (x + 0x80 + (y * 4)) + +/********************************************************************** +* ctrl register definitions +**********************************************************************/ +/* Bit for enabling RTC match 0 interrupt */ +#define RTC_MATCH0_EN _BIT(0) +/* Bit for enabling RTC match 1 interrupt */ +#define RTC_MATCH1_EN _BIT(1) +/* Bit for enabling ONSW signal on match 0 */ +#define RTC_ONSW_MATCH0_EN _BIT(2) +/* Bit for enabling ONSW signal on match 1 */ +#define RTC_ONSW_MATCH1_EN _BIT(3) +/* Bit for performing an RC software reset, must be cleared after set */ +#define RTC_SW_RESET _BIT(4) +/* Bit for disabling 1Hz up/down counters */ +#define RTC_CNTR_DIS _BIT(6) +/* Bit for forcing ONSW high (1) or default state */ +#define RTC_ONSW_FORCE_HIGH _BIT(7) + +/********************************************************************** +* intstat register definitions +**********************************************************************/ +/* Bit for match 0 interrupt status or clearing latched state */ +#define RTC_MATCH0_INT_STS _BIT(0) +/* Bit for match 1 interrupt status or clearing latched state */ +#define RTC_MATCH1_INT_STS _BIT(1) +/* Bit for ONSW interrupt status or clearing ONSW high state */ +#define RTC_ONSW_INT_STS _BIT(2) + +/********************************************************************** +* key register definitions +**********************************************************************/ +/* RTC key register enable value (must be loaded for ONSW to work) */ +#define RTC_KEY_ONSW_LOADVAL 0xB5C13F27 + +#endif /* LPC32XX_RTC_H */ diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_sdcard.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_sdcard.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_sdcard.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_sdcard.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,179 @@ +/* + * asm-arm/arch-lpc32xx/lpc32xx_sdcard.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 LPC32XX_SDCARD_H +#define LPC32XX_SDCARD_H + +#define _BIT(n) (1 << (n)) + +/********************************************************************** +* SD Card controller register offsets +**********************************************************************/ + +#define SD_POWER(x) (x + 0x00) +#define SD_CLOCK(x) (x + 0x04) +#define SD_ARG(x) (x + 0x08) +#define SD_CMD(x) (x + 0x10) +#define SD_RESPCMD(x) (x + 0x14) +#define SD_RESP(x) (x + 0x18) +#define SD_DTIMER(x) (x + 0x28) +#define SD_DLEN(x) (x + 0x2C) +#define SD_DCTRL(x) (x + 0x30) +#define SD_DCNT(x) (x + 0x34) +#define SD_STATUS(x) (x + 0x38) +#define SD_CLEAR(x) (x + 0x3C) +#define SD_MASK0(x) (x + 0x40) +#define SD_MASK1(x) (x + 0x44) +#define SD_FIFOCNT(x) (x + 0x4C) +#define SD_FIFO(x) (x + 0x80) + +/********************************************************************** +* sd_power register definitions +**********************************************************************/ +/* SD bit for enabling open drain mode (1) or pushpull mode (0) */ +#define SD_OPENDRAIN_EN _BIT(6) +/* SD power control mode: power off */ +#define SD_POWER_OFF_MODE 0x0 +/* SD power control mode: power up */ +#define SD_POWER_UP_MODE 0x2 +/* SD power control mode: power on */ +#define SD_POWER_ON_MODE 0x3 +/* SD power control mode mask */ +#define SD_POWER_MODE_MASK 0x3 + +/********************************************************************** +* sd_clock register definitions +**********************************************************************/ +/* SD bit for enabling side bus mode */ +#define SD_WIDEBUSMODE_EN _BIT(11) +/* SD bit for enabling SDCLK clock bypass */ +#define SD_SDCLK_BYPASS _BIT(10) +/* SD bit for enabling clock throttling during idle states */ +#define SD_SDCLK_PWRSAVE _BIT(9) +/* SD bit for enabling the SD clock */ +#define SD_SDCLK_EN _BIT(8) +/* SD clock divider bit mask */ +#define SD_CLKDIV_MASK 0xFF + +/********************************************************************** +* sd_cmd register definitions +**********************************************************************/ +/* SD bit for enabling command path state machine */ +#define SD_CPST_EN _BIT(10) +/* SD bit for wait for CMDPEND prior to sending command */ +#define SD_CMDPEND_WAIT _BIT(9) +/* SD bit for enabling card interrupt request (without timeout) */ +#define SD_INTERRUPT_EN _BIT(8) +/* SD bit for enabling 136-bit response support */ +#define SD_LONGRESP_EN _BIT(7) +/* SD bit for enabling response support */ +#define SD_RESPONSE _BIT(6) +/* SD command mask */ +#define SD_CMD_MASK 0x3F + +/********************************************************************** +* sd_dctrl register definitions +**********************************************************************/ +/* SD data transfer blocksize of 1 byte */ +#define SD_BLKSIZE_1BYTE 0x00 +/* SD data transfer blocksize of 2 bytes */ +#define SD_BLKSIZE_2BYTES 0x10 +/* SD data transfer blocksize of 4 bytes */ +#define SD_BLKSIZE_4BYTES 0x20 +/* SD data transfer blocksize of 8 bytes */ +#define SD_BLKSIZE_8BYTES 0x30 +/* SD data transfer blocksize of 16 bytes */ +#define SD_BLKSIZE_16BYTES 0x40 +/* SD data transfer blocksize of 32 bytes */ +#define SD_BLKSIZE_32BYTES 0x50 +/* SD data transfer blocksize of 64 bytes */ +#define SD_BLKSIZE_64BYTES 0x60 +/* SD data transfer blocksize of 128 bytes */ +#define SD_BLKSIZE_128BYTES 0x70 +/* SD data transfer blocksize of 256 bytes */ +#define SD_BLKSIZE_256BYTES 0x80 +/* SD data transfer blocksize of 512 bytes */ +#define SD_BLKSIZE_512BYTES 0x90 +/* SD data transfer blocksize of 1024 bytes */ +#define SD_BLKSIZE_1024BYTES 0xA0 +/* SD data transfer blocksize of 2048 bytes */ +#define SD_BLKSIZE_2048BYTES 0xB0 +/* SD bit for enabling DMA */ +#define SD_DMA_EN _BIT(3) +/* SD bit for enabling a stream transfer */ +#define SD_STREAM_EN _BIT(2) +/* SD direction bit (1 = receive, 0 = transmit) */ +#define SD_DIR_FROMCARD _BIT(1) +/* SD data transfer enable bit */ +#define SD_DATATRANSFER_EN _BIT(0) + +/********************************************************************** +* sd_status register definitions +* sd_clear register definitions (bits 0..10 only) +* sd_mask0, sd_mask1 register definitions +**********************************************************************/ +/* SD bit for data receive FIFO NOT empty status */ +#define SD_FIFO_RXDATA_AVAIL _BIT(21) +/* SD bit for data transmit FIFO NOT empty status */ +#define SD_FIFO_TXDATA_AVAIL _BIT(20) +/* SD bit for data receive FIFO empty status */ +#define SD_FIFO_RXDATA_EMPTY _BIT(19) +/* SD bit for data transmit FIFO empty status */ +#define SD_FIFO_TXDATA_EMPTY _BIT(18) +/* SD bit for data receive FIFO full status */ +#define SD_FIFO_RXDATA_FULL _BIT(17) +/* SD bit for data transmit FIFO full status */ +#define SD_FIFO_TXDATA_FULL _BIT(16) +/* SD bit for data receive FIFO half-full status */ +#define SD_FIFO_RXDATA_HFULL _BIT(15) +/* SD bit for data transmit FIFO half-empty status */ +#define SD_FIFO_TXDATA_HEMPTY _BIT(14) +/* SD bit for data receive in progress status */ +#define SD_RX_INPROGRESS _BIT(13) +/* SD bit for data transmit in progress status */ +#define SD_TX_INPROGRESS _BIT(12) +/* SD bit for command transfer in progress status */ +#define SD_CMD_INPROGRESS _BIT(11) +/* SD bit for data block send/received complete (CRC good) status */ +#define SD_DATABLK_END _BIT(10) +/* SD bit for start bit detection error status */ +#define SD_STARTBIT_ERR _BIT(9) +/* SD bit for data end (data counter is 0) status */ +#define SD_DATA_END _BIT(8) +/* SD bit for command sent status */ +#define SD_CMD_SENT _BIT(7) +/* SD bit for command response received (CRC good) status */ +#define SD_CMD_RESP_RECEIVED _BIT(6) +/* SD bit for data receive FIFO overflow status */ +#define SD_FIFO_RXDATA_OFLOW _BIT(5) +/* SD bit for data transmit FIFO underflow status */ +#define SD_FIFO_TXDATA_UFLOW _BIT(4) +/* SD bit for data timeout status */ +#define SD_DATA_TIMEOUT _BIT(3) +/* SD bit for command timeout status */ +#define SD_CMD_TIMEOUT _BIT(2) +/* SD bit for data CRC failure status */ +#define SD_DATA_CRC_FAIL _BIT(1) +/* SD bit for command CRC failure status */ +#define SD_CMD_CRC_FAIL _BIT(0) + +#endif /* LPC32XX_SDCARD_H */ diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_slcnand.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_slcnand.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_slcnand.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_slcnand.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,105 @@ +/* + * asm-arm/arch-lpc32xx/lpc32xx_slcnand.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 LPC32XX_SLCNAND_H +#define LPC32XX_SLCNAND_H + +#define _BIT(n) (1 << (n)) + +/********************************************************************** +* SLC NAND controller register offsets +**********************************************************************/ + +#define SLC_DATA(x) (x + 0x000) +#define SLC_ADDR(x) (x + 0x004) +#define SLC_CMD(x) (x + 0x008) +#define SLC_STOP(x) (x + 0x00C) +#define SLC_CTRL(x) (x + 0x010) +#define SLC_CFG(x) (x + 0x014) +#define SLC_STAT(x) (x + 0x018) +#define SLC_INT_STAT(x) (x + 0x01C) +#define SLC_IEN(x) (x + 0x020) +#define SLC_ISR(x) (x + 0x024) +#define SLC_ICR(x) (x + 0x028) +#define SLC_TAC(x) (x + 0x02C) +#define SLC_TC(x) (x + 0x030) +#define SLC_ECC(x) (x + 0x034) +#define SLC_DMA_DATA(x) (x + 0x038) + +/********************************************************************** +* slc_ctrl register definitions +**********************************************************************/ +#define SLCCTRL_SW_RESET _BIT(2) /* Reset the NAND controller bit */ +#define SLCCTRL_ECC_CLEAR _BIT(1) /* Reset ECC bit */ +#define SLCCTRL_DMA_START _BIT(0) /* Start DMA channel bit */ + +/********************************************************************** +* slc_cfg register definitions +**********************************************************************/ +#define SLCCFG_CE_LOW _BIT(5) /* Force CE low bit */ +#define SLCCFG_DMA_ECC _BIT(4) /* Enable DMA ECC bit */ +#define SLCCFG_ECC_EN _BIT(3) /* ECC enable bit */ +#define SLCCFG_DMA_BURST _BIT(2) /* DMA burst bit */ +#define SLCCFG_DMA_DIR _BIT(1) /* DMA write(0)/read(1) bit */ +#define SLCCFG_WIDTH _BIT(0) /* External device width, 0=8bit */ + +/********************************************************************** +* slc_stat register definitions +**********************************************************************/ +#define SLCSTAT_DMA_FIFO _BIT(2) /* DMA FIFO has data bit */ +#define SLCSTAT_SLC_FIFO _BIT(1) /* SLC FIFO has data bit */ +#define SLCSTAT_NAND_READY _BIT(0) /* NAND device is ready bit */ + +/********************************************************************** +* slc_int_stat, slc_ien, slc_isr, and slc_icr register definitions +**********************************************************************/ +#define SLCSTAT_INT_TC _BIT(1) /* Transfer count bit */ +#define SLCSTAT_INT_RDY_EN _BIT(0) /* Ready interrupt bit */ + +/********************************************************************** +* slc_tac register definitions +**********************************************************************/ +/* Clock setting for RDY write sample wait time in 2*n clocks */ +#define SLCTAC_WDR(n) (((n) & 0xF) << 28) +/* Write pulse width in clocks cycles, 1 to 16 clocks */ +#define SLCTAC_WWIDTH(n) (((n) & 0xF) << 24) +/* Write hold time of control and data signals, 1 to 16 clocks */ +#define SLCTAC_WHOLD(n) (((n) & 0xF) << 20) +/* Write setup time of control and data signals, 1 to 16 clocks */ +#define SLCTAC_WSETUP(n) (((n) & 0xF) << 16) +/* Clock setting for RDY read sample wait time in 2*n clocks */ +#define SLCTAC_RDR(n) (((n) & 0xF) << 12) +/* Read pulse width in clocks cycles, 1 to 16 clocks */ +#define SLCTAC_RWIDTH(n) (((n) & 0xF) << 8) +/* Read hold time of control and data signals, 1 to 16 clocks */ +#define SLCTAC_RHOLD(n) (((n) & 0xF) << 4) +/* Read setup time of control and data signals, 1 to 16 clocks */ +#define SLCTAC_RSETUP(n) (((n) & 0xF) << 0) + +/********************************************************************** +* slc_ecc register definitions +**********************************************************************/ +/* ECC line party fetch macro */ +#define SLCECC_TO_LINEPAR(n) (((n) >> 6) & 0x7FFF) +#define SLCECC_TO_COLPAR(n) ((n) & 0x3F) + +#endif /* LPC32XX_SLCNAND_H */ diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_ssp.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_ssp.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_ssp.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_ssp.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,140 @@ +/* + * asm-arm/arch-lpc32xx/lpc32xx_ssp.h + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 LPC32XX_SSP_H +#define LPC32XX_SSP_H + +#define _BIT(n) (1 << (n)) +#define _SBF(f,v) (((v)) << (f)) + +/********************************************************************** +* Key scanner register offsets +**********************************************************************/ + +#define SSP_CR0(x) (x + 0x00) +#define SSP_CR1(x) (x + 0x04) +#define SSP_DATA(x) (x + 0x08) +#define SSP_SR(x) (x + 0x0C) +#define SSP_CPSR(x) (x + 0x10) +#define SSP_IMSC(x) (x + 0x14) +#define SSP_RIS(x) (x + 0x18) +#define SSP_MIS(x) (x + 0x1C) +#define SSP_ICR(x) (x + 0x20) +#define SSP_DMACR(x) (x + 0x24) + +/*********************************************************************** + * cr0 register definitions + **********************************************************************/ +/* SSP data size load macro, must be 4 bits to 16 bits */ +#define SSP_CR0_DSS(n) _SBF(0, (((n) - 1) & 0xF)) // Data Size Select +/* SSP control 0 Motorola SPI mode */ +#define SSP_CR0_FRF_SPI 0x00000000 +/* SSP control 0 TI synchronous serial mode */ +#define SSP_CR0_FRF_TI 0x00000010 +/* SSP control 0 National Microwire mode */ +#define SSP_CR0_FRF_NS 0x00000020 +/* SSP control 0 protocol mask */ +#define SSP_CR0_PRT_MSK 0x00000030 +/* SPI clock polarity bit (used in SPI mode only), (1) = maintains the + bus clock high between frames, (0) = low */ +#define SSP_CR0_CPOL(n) _SBF(6, ((n) & 0x01)) +/* SPI clock out phase bit (used in SPI mode only), (1) = captures data + on the second clock transition of the frame, (0) = first */ +#define SSP_CR0_CPHA(n) _SBF(7, ((n) & 0x01)) +/* SSP serial clock rate value load macro, divider rate is + PERIPH_CLK / (cpsr * (SCR + 1)) */ +#define SSP_CR0_SCR(n) _SBF(8, ((n) & 0xFF)) + +/*********************************************************************** + * cr1 register definitions + **********************************************************************/ +/* SSP control 1 loopback mode enable bit */ +#define SSP_CR1_LBM _BIT(0) +/* SSP control 1 enable bit */ +#define SSP_CR1_SSE(n) _SBF(1, ((n) & 0x01)) +#define SSP_CR1_SSP_ENABLE _BIT(1) +#define SSP_CR1_SSP_DISABLE 0 +/* SSP control 1 master/slave bit, (1) = master, (0) = slave */ +#define SSP_CR1_MS _BIT(2) +#define SSP_CR1_MASTER 0 +#define SSP_CR1_SLAVE _BIT(2) +/* SSP control 1 slave out disable bit, disables transmit line in slave + mode */ +#define SSP_CR1_SOD _BIT(3) + +/*********************************************************************** + * data register definitions + **********************************************************************/ +/* SSP data load macro */ +#define SSP_DATAMASK(n) ((n) & 0xFFFF) + +/*********************************************************************** + * SSP status register (sr) definitions + **********************************************************************/ +/* SSP status TX FIFO Empty bit */ +#define SSP_SR_TFE _BIT(0) +/* SSP status TX FIFO not full bit */ +#define SSP_SR_TNF _BIT(1) +/* SSP status RX FIFO not empty bit */ +#define SSP_SR_RNE _BIT(2) +/* SSP status RX FIFO full bit */ +#define SSP_SR_RFF _BIT(3) +/* SSP status SSP Busy bit */ +#define SSP_SR_BSY _BIT(4) + +/*********************************************************************** + * SSP clock prescaler register (cpsr) definitions + **********************************************************************/ +/* SSP clock prescaler load macro */ +#define SSP_CPSR_CPDVSR(n) _SBF(0, (n) & 0xFE) + +/*********************************************************************** + * SSP interrupt registers (imsc, ris, mis, icr) definitions + **********************************************************************/ +/* SSP interrupt bit for RX FIFO overflow */ +#define SSP_IMSC_RORIM _BIT(0) +#define SSP_RIS_RORRIS _BIT(0) +#define SSP_MIS_RORMIS _BIT(0) +#define SSP_ICR_RORIC _BIT(0) +/* SSP interrupt bit for RX FIFO not empty and has a data timeout */ +#define SSP_IMSC_RTIM _BIT(1) +#define SSP_RIS_RTRIS _BIT(1) +#define SSP_MIS_RTMIS _BIT(1) +#define SSP_ICR_RTIC _BIT(1) +/* SSP interrupt bit for RX FIFO half full */ +#define SSP_IMSC_RXIM _BIT(2) +#define SSP_RIS_RXRIS _BIT(2) +#define SSP_MIS_RXMIS _BIT(2) +/* SSP interrupt bit for TX FIFO half empty */ +#define SSP_IMSC_TXIM _BIT(3) +#define SSP_RIS_TXRIS _BIT(3) +#define SSP_MIS_TXMIS _BIT(3) + +/*********************************************************************** + * SSP DMA enable register (dmacr) definitions + **********************************************************************/ +/* SSP bit for enabling RX DMA */ +#define SSP_DMA_RXDMAEN _BIT(0) +/* SSP bit for enabling TX DMA */ +#define SSP_DMA_TXDMAEN _BIT(1) + +#define SSP_FIFO_DEPTH_WORDS 8 + +#endif /* LPC3250_SSP_H */ diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_timer.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_timer.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_timer.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_timer.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,140 @@ +/* + * asm-arm/arch-lpc32xx/lpc32xx_timer.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 LPC32XX_TIMER_H +#define LPC32XX_TIMER_H + +/********************************************************************** +* Timer/counter register offsets +**********************************************************************/ + +#define TIMER_IR(x) (x + 0x00) +#define TIMER_TCR(x) (x + 0x04) +#define TIMER_TC(x) (x + 0x08) +#define TIMER_PR(x) (x + 0x0C) +#define TIMER_PC(x) (x + 0x10) +#define TIMER_MCR(x) (x + 0x14) +#define TIMER_MR0(x) (x + 0x18) +#define TIMER_MR1(x) (x + 0x1C) +#define TIMER_MR2(x) (x + 0x20) +#define TIMER_MR3(x) (x + 0x24) +#define TIMER_CCR(x) (x + 0x28) +#define TIMER_CR0(x) (x + 0x2C) +#define TIMER_CR1(x) (x + 0x30) +#define TIMER_CR2(x) (x + 0x34) +#define TIMER_CR3(x) (x + 0x38) +#define TIMER_EMR(x) (x + 0x3C) +#define TIMER_CTCR(x) (x + 0x70) + +/********************************************************************** +* ir register definitions +* Write a '1' to clear interrupt, reading a '1' indicates active int +**********************************************************************/ +/* Macro for getting a timer match interrupt bit */ +#define TIMER_CNTR_MTCH_BIT(n) (1 << ((n) & 0x3)) + +/* Macro for getting a capture event interrupt bit */ +#define TIMER_CNTR_CAPT_BIT(n) (1 << (4 + ((n) & 0x3))) + +/********************************************************************** +* tcr register definitions +**********************************************************************/ +/* Timer/counter enable bit */ +#define TIMER_CNTR_TCR_EN 0x1 + +/* Timer/counter reset bit */ +#define TIMER_CNTR_TCR_RESET 0x2 + +/********************************************************************** +* mcr register definitions +**********************************************************************/ +/* Bit location for interrupt on MRx match, n = 0 to 3 */ +#define TIMER_CNTR_MCR_MTCH(n) (0x1 << ((n) * 3)) + +/* Bit location for reset on MRx match, n = 0 to 3 */ +#define TIMER_CNTR_MCR_RESET(n) (0x1 << (((n) * 3) + 1)) + +/* Bit location for stop on MRx match, n = 0 to 3 */ +#define TIMER_CNTR_MCR_STOP(n) (0x1 << (((n) * 3) + 2)) + +/********************************************************************** +* ccr register definitions +**********************************************************************/ +/* Bit location for CAP.n on CRx rising edge, n = 0 to 3 */ +#define TIMER_CNTR_CCR_CAPNRE(n) (0x1 << ((n) * 3)) + +/* Bit location for CAP.n on CRx falling edge, n = 0 to 3 */ +#define TIMER_CNTR_CCR_CAPNFE(n) (0x1 << (((n) * 3) + 1)) + +/* Bit location for CAP.n on CRx interrupt enable, n = 0 to 3 */ +#define TIMER_CNTR_CCR_CAPNI(n) (0x1 << (((n) * 3) + 2)) + +/********************************************************************** +* emr register definitions +**********************************************************************/ +/* Bit location for output state change of MAT.n when external match + happens, n = 0 to 3 */ +#define TIMER_CNTR_EMR_DRIVE(n) (1 << (n)) + +/* Macro for setting MAT.n soutput state */ +#define TIMER_CNTR_EMR_DRIVE_SET(n, s) (((s) & 0x1) << (n)) + +/* Output state change of MAT.n when external match happens */ +#define TIMER_CNTR_EMR_NOTHING 0x0 +#define TIMER_CNTR_EMR_LOW 0x1 +#define TIMER_CNTR_EMR_HIGH 0x2 +#define TIMER_CNTR_EMR_TOGGLE 0x3 + +/* Macro for setting for the MAT.n change state bits */ +#define TIMER_CNTR_EMR_EMC_SET(n, s) (((s) & 0x3) << (4 + ((n) * 2))) + +/* Mask for the MAT.n change state bits */ +#define TIMER_CNTR_EMR_EMC_MASK(n) (0x3 << (4 + ((n) * 2))) + +/********************************************************************** +* ctcr register definitions +**********************************************************************/ +/* Mask to get the Counter/timer mode bits */ +#define TIMER_CNTR_CTCR_MODE_MASK 0x3 + +/* Mask to get the count input select bits */ +#define TIMER_CNTR_CTCR_INPUT_MASK 0xC + +/* Counter/timer modes */ +#define TIMER_CNTR_CTCR_TIMER_MODE 0x0 +#define TIMER_CNTR_CTCR_TCINC_MODE 0x1 +#define TIMER_CNTR_CTCR_TCDEC_MODE 0x2 +#define TIMER_CNTR_CTCR_TCBOTH_MODE 0x3 + +/* Count input selections */ +#define TIMER_CNTR_CTCR_INPUT_CAP0 0x0 +#define TIMER_CNTR_CTCR_INPUT_CAP1 0x1 +#define TIMER_CNTR_CTCR_INPUT_CAP2 0x2 +#define TIMER_CNTR_CTCR_INPUT_CAP3 0x3 + +/* Macro for setting the counter/timer mode */ +#define TIMER_CNTR_SET_MODE(n) ((n) & 0x3) + +/* Macro for setting the count input select */ +#define TIMER_CNTR_SET_INPUT(n) (((n) & 0x3) << 2) + +#endif /* LPC32XX_TIMER_H */ diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_tsc.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_tsc.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_tsc.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_tsc.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,188 @@ +/* + * asm-arm/arch-lpc32xx/lpc32xx_tsc.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 LPC32xx_TSC_H +#define LPC32xx_TSC_H + +#define _BIT(n) (1 << (n)) +#define _SBF(f,v) (((v)) << (f)) + +/********************************************************************** +* Touchscreen controller register offsets +**********************************************************************/ + +#define TSC_STAT(x) (x + 0x00) +#define TSC_SEL(x) (x + 0x04) +#define TSC_CON(x) (x + 0x08) +#define TSC_FIFO(x) (x + 0x0C) +#define TSC_DTR(x) (x + 0x10) +#define TSC_RTR(x) (x + 0x14) +#define TSC_UTR(x) (x + 0x18) +#define TSC_TTR(x) (x + 0x1C) +#define TSC_DXP(x) (x + 0x20) +#define TSC_MIN_X(x) (x + 0x24) +#define TSC_MAX_X(x) (x + 0x28) +#define TSC_MIN_Y(x) (x + 0x2C) +#define TSC_MAX_Y(x) (x + 0x30) +#define TSC_AUX_UTR(x) (x + 0x34) +#define TSC_AUX_MIN(x) (x + 0x38) +#define TSC_AUX_MAX(x) (x + 0x3C) +#define TSC_AUX_VAL(x) (x + 0x44) +#define TSC_ADC_DAT(x) (x + 0x48) + +/********************************************************************** +* tsc_stat register definitions +**********************************************************************/ +#define TSC_STAT_FIFO_OVRRN _BIT(8) /* FIFO overrun status */ +#define TSC_STAT_FIFO_EMPTY _BIT(7) /* FIFO empty status */ +#define TSC_STAT_ADC_STAT_MASK 0x00000070 /* FIFO ADC status mask */ +#define TSC_STAT_TSC_STAT_MASK 0x0000000F /* FIFO TSC status mask */ + +/* The register masked with TSC_STAT_ADC_STAT_MASK will give these + status values. These statuses are only valid when AUTO_EN in the + touch control register is enabled. */ +#define TSC_STAT_ADC_SCAN_STOP_STS 0x00000000 +#define TSC_STAT_ADC_WAIT_RISE_STS 0x00000010 +#define TSC_STAT_ADC_WAIT_SAMPLE_STS 0x00000020 +#define TSC_STAT_ADC_WAIT_ACCURACY_STS 0x00000030 +#define TSC_STAT_ADC_NOT_READY_STS 0x00000040 + +/* The register masked with TSC_STAT_TSC_STAT_MASK will give these + status values. These statuses are only valid when AUTO_EN in the + touch control register is not enabled. */ +#define TSC_STAT_ADC_TSC_INACTIVE_STS 0x00000000 +#define TSC_STAT_ADC_TSC_AUTO_STS 0x00000001 +#define TSC_STAT_ADC_TSC_AUX_DETECT_STS 0x00000002 +#define TSC_STAT_ADC_TSC_WAIT_DELAY_STS 0x00000003 +#define TSC_STAT_ADC_TSC_MEASURE_X_STS 0x00000004 +#define TSC_STAT_ADC_TSC_MEASURE_Y_STS 0x00000005 +#define TSC_STAT_ADC_TSC_MEASURE_AUX_STS 0x00000006 +#define TSC_STAT_ADC_TSC_DRAIN_X_STS 0x00000007 +#define TSC_STAT_ADC_TSC_TOUCH_DETECT_STS 0x00000008 +#define TSC_STAT_ADC_TSC_CHK_FIFO_MT_STS 0x00000009 +#define TSC_STAT_ADC_TSC_WAIT_UPD_TMR_STS 0x0000000A +#define TSC_STAT_ADC_TSC_UPD_TIMER_AUC_STS 0x0000000C + +/********************************************************************** +* adc_sel register definitions +**********************************************************************/ +#define TSC_ADCSEL_TSREF_MINUS_TO_XM _SBF(8, 0) +#define TSC_ADCSEL_TSREF_MINUS_TO_YM _SBF(8, 1) +#define TSC_ADCSEL_TSREF_MINUS_TO_VSS _SBF(8, 2) +#define TSC_ADCSEL_TSREF_PLUS_TO_XP _SBF(6, 0) +#define TSC_ADCSEL_TSREF_PLUS_TO_YP _SBF(6, 1) +#define TSC_ADCSEL_TSREF_PLUS_TO_VDDTS _SBF(6, 2) +#define TSC_ADCSEL_TSIN_TO_YM _SBF(4, 0) +#define TSC_ADCSEL_TSIN_TO_XM _SBF(4, 1) +#define TSC_ADCSEL_TSIN_TO_AUX _SBF(4, 2) +#define TSC_ADCSEL_YM_TO_GND _BIT(3) +#define TSC_ADCSEL_YP_TO_VDDTS _BIT(2) +#define TSC_ADCSEL_XM_TO_GND _BIT(1) +#define TSC_ADCSEL_XP_TO_VDDTS _BIT(0) + +#define ADC_SEL_MASK 0x284 +#define TSC_SEL_MASK 0x4 +#define ADCSEL_CH_0 0x0 +#define ADCSEL_CH_1 0x10 +#define ADCSEL_CH_2 0x20 + +/********************************************************************** +* adc_con register definitions +**********************************************************************/ +#define TSC_ADCCON_IRQ_TO_FIFO_1 _SBF(11, 0) +#define TSC_ADCCON_IRQ_TO_FIFO_4 _SBF(11, 1) +#define TSC_ADCCON_IRQ_TO_FIFO_8 _SBF(11, 2) +#define TSC_ADCCON_IRQ_TO_FIFO_16 _SBF(11, 3) +#define TSC_ADCCON_TS_AUX_EN _BIT(10) + +#define TSC_FIFO_MSK 0x1800 + +/* Allowable sample sizes are 3 to 10 bits */ +#define TSC_ADCCON_X_SAMPLE_SIZE(s) _SBF(7, (10 - s)) +#define TSC_ADCCON_Y_SAMPLE_SIZE(s) _SBF(4, (10 - s)) + +#define TSC_ADCCON_POS_DET _BIT(3) +#define TSC_ADCCON_POWER_UP _BIT(2) +#define TSC_ADCCON_ADC_STROBE _BIT(1) +#define TSC_ADCCON_AUTO_EN _BIT(0) + +/********************************************************************** +* tsc_fifo register definitions +**********************************************************************/ +#define TSC_FIFO_TS_P_LEVEL _BIT(31) +#define TSC_FIFO_TS_FIFO_EMPTY _BIT(30) +#define TSC_FIFO_TS_FIFO_OVERRUN _BIT(29) +#define TSC_FIFO_NORMALIZE_X_VAL(x) ((x & 0x03FF0000) >> 16) +#define TSC_FIFO_NORMALIZE_Y_VAL(y) (y & 0x000003FF) + +/********************************************************************** +* tsc_dtr register definitions +**********************************************************************/ +#define TSC_DTR_DELAY_TIME(d) (d) + +/********************************************************************** +* tsc_rtr register definitions +**********************************************************************/ +#define TSC_RTR_RISE_TIME(d) (d) + +/********************************************************************** +* tsc_utr register definitions +**********************************************************************/ +#define TSC_UTR_UPDATE_TIME(d) (d) + +/********************************************************************** +* tsc_ttr register definitions +**********************************************************************/ +#define TSC_TTR_TOUCH_TIME(d) (d) + +/********************************************************************** +* tsc_dxp register definitions +**********************************************************************/ +#define TSC_DXP_DRAINX_TIME(d) (d) + +/********************************************************************** +* tsc_min_x, tsc_max_x, tsc_min_y, and tsc_max_y register definitions +**********************************************************************/ +#define TSC_DTR_MINX_VALUE(d) (d) +#define TSC_DTR_MAXX_VALUE(d) (d) +#define TSC_DTR_MINY_VALUE(d) (d) +#define TSC_DTR_MAXY_VALUE(d) (d) + +/********************************************************************** +* tsc_aux_utr register definitions +**********************************************************************/ +#define TSC_AUX_UTR_UPDATE_TIME(d) (d) + +/********************************************************************** +* tsc_aux_min, tsc_aux_max, and tsc_aux_max register definitions +**********************************************************************/ +#define TSC_AUX_MIN_VALUE(d) (d) +#define TSC_AUX_MAX_VALUE(d) (d) +#define TSC_AUX_VALUE(d) (d) + +/********************************************************************** +* adc_dat register definitions +**********************************************************************/ +#define TSC_ADCDAT_P_LEVEL _BIT(10) +#define TSC_ADCDAT_VALUE_MASK 0x000003FF + +#endif /* LPC32xx_TSC_H */ diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_uart.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_uart.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_uart.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_uart.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,239 @@ +/* + * asm-arm/arch-lpc32xx/lpc32xx_uart.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 LPC32XX_STANDARD_UART_H +#define LPC32XX_STANDARD_UART_H + +#define _BIT(n) (1 << (n)) + +/********************************************************************** +* Standard UART register offsets +**********************************************************************/ + +/* Standard UART register offsets */ +#define UART_DLL_FIFO(x) (x + 0x00) +#define UART_DLM_IER(x) (x + 0x04) +#define UART_IIR_FCR(x) (x + 0x08) +#define UART_LCR_(x) (x + 0x0C) +#define UART_MODEM_CTRL(x) (x + 0x10) +#define UART_LSR_(x) (x + 0x14) +#define UART_MODEM_STATUS(x) (x + 0x18) +#define UART_RXLEV(x) (x + 0x1C) + +/* UART control structure offsets */ +#define UARTCTL_CTRL(x) (x + 0x00) +#define UARTCTL_CLKMODE(x) (x + 0x04) +#define UARTCTL_CLOOP(x) (x + 0x08) + +/********************************************************************** +* dll and dlm register definitions +**********************************************************************/ +/* Macro for loading most and least significant halfs of divisors */ +#define UART_LOAD_DM(div) ((div) & 0xFF) + +/********************************************************************** +* ier register definitions +**********************************************************************/ +/* Bit for enabling the modem status interrupt */ +#define UART_IER_MODEM_STS _BIT(3) +/* Bit for enabling the RX line status interrupt(s) */ +#define UART_IER_RXLINE_STS _BIT(2) +/* Bit for enabling the transmit holding register empty interrupt */ +#define UART_IER_THRE _BIT(1) +/* Bit for enabling the receive data available (RDA) interrupt */ +#define UART_IER_RDA _BIT(0) + +/********************************************************************** +* iir register definitions +**********************************************************************/ +/* Bit for masking interrupt pending status */ +#define UART_IIR_INT_PENDING _BIT(0) +/* Mask for getting interrupt source */ +#define UART_IIR_INT_MASK 0xE +/* Interrupt sources */ +#define UART_IIR_MODEM_STS 0x0 +#define UART_IIR_INTSRC_THRE 0x2 +#define UART_IIR_INTSRC_RDA 0x4 +#define UART_IIR_INTSRC_RXLINE 0x6 +#define UART_IIR_INTSRC_CTI 0xC /* Character timeout */ +/* Interrupt bits mask word */ +#define UART_IIR_INTSRC_MASK 0xE + +/********************************************************************** +* fcr register definitions +**********************************************************************/ +/* Receive FIFO trigger level selections */ +#define UART_FCR_RXFIFO_TL16 0x0 +#define UART_FCR_RXFIFO_TL32 _BIT(6) +#define UART_FCR_RXFIFO_TL48 _BIT(7) +#define UART_FCR_RXFIFO_TL60 (_BIT(7) | _BIT(6)) +/* Transmit FIFO trigger level selections */ +#define UART_FCR_TXFIFO_TL0 0x0 +#define UART_FCR_TXFIFO_TL4 _BIT(4) +#define UART_FCR_TXFIFO_TL8 _BIT(5) +#define UART_FCR_TXFIFO_TL16 (_BIT(5) | _BIT(4)) +/* Enable FIFO bit - must be set with UART_FCR_FIFO_EN */ +#define UART_FCR_FIFO_CTRL _BIT(3) +/* Clear TX FIFO bit */ +#define UART_FCR_TXFIFO_FLUSH _BIT(2) +/* Clear RX FIFO bit */ +#define UART_FCR_RXFIFO_FLUSH _BIT(1) +/* Enable FIFO bit - must be set with UART_FCR_FIFO_CTRL */ +#define UART_FCR_FIFO_EN _BIT(0) + +/********************************************************************** +* lcr register definitions +**********************************************************************/ +/* Bit for enabling divisor latch and IER register */ +#define UART_LCR_DIVLATCH_EN _BIT(7) +/* Bit for enabling break transmission (forces TX low) */ +#define UART_LCR_BREAK_EN _BIT(6) +/* Parity selection */ +#define UART_LCR_PARITY_ODD 0x0 +#define UART_LCR_PARITY_EVEN _BIT(4) +#define UART_LCR_PARITY_FORCE1 _BIT(5) +#define UART_LCR_PARITY_FORCE0 (_BIT(5) | _BIT(4)) +/* Parity selection mask */ +#define UART_LCR_PARITY_MASK (_BIT(5) | _BIT(4)) +/* Parity enable bit */ +#define UART_LCR_PARITY_ENABLE _BIT(3) +/* Stop bit selection */ +#define UART_LCR_STOP1BIT 0x0 +#define UART_LCR_STOP2BITS _BIT(2) +/* Word length selections */ +#define UART_LCR_WLEN_5BITS 0x0 +#define UART_LCR_WLEN_6BITS _BIT(0) +#define UART_LCR_WLEN_7BITS _BIT(1) +#define UART_LCR_WLEN_8BITS (_BIT(1) | _BIT(0)) +/* Word length mask */ +#define UART_LCR_WLEN_MASK (_BIT(1) | _BIT(0)) + +/********************************************************************** +* modem_ctrl register definitions +**********************************************************************/ +/* Bit for enabling modem loopback mode */ +#define UART_MDMC_LOOPB_EN _BIT(4) +/* Bit for driving RTS low */ +#define UART_MDMC_RTS_LOW _BIT(1) +/* Bit for driving DTR low */ +#define UART_MDMC_DTR_LOW _BIT(0) + +/********************************************************************** +* lsr register definitions +**********************************************************************/ +/* Bit for masking FIFO RX error status */ +#define UART_LSR_FIFORX_ERR _BIT(7) +/* Bit for masking transmitter empty status */ +#define UART_LSR_TEMT_ _BIT(6) +/* Bit for masking transmit FIFO trip point status */ +#define UART_LSR_THRE_ _BIT(5) +/* Bit for masking break interrupt status */ +#define UART_LSR_BI_ _BIT(4) +/* Bit for masking framing error status */ +#define UART_LSR_FR_ _BIT(3) +/* Bit for masking parity error status */ +#define UART_LSR_PE_ _BIT(2) +/* Bit for masking RX FIFO overrun error status */ +#define UART_LSR_OE_ _BIT(1) +/* Bit for masking RX FIFO empty status */ +#define UART_LSR_RDR_ _BIT(0) + +/********************************************************************** +* modem_status register definitions +**********************************************************************/ +/* Bit for masking data carrier detect state */ +#define UART_MDMS_DCD _BIT(7) +/* Bit for masking ring indicator state */ +#define UART_MDMS_RI _BIT(6) +/* Bit for masking data set ready state */ +#define UART_MDMS_DSR _BIT(5) +/* Bit for masking clear to send state */ +#define UART_MDMS_CTS _BIT(4) +/* Bit for detecting state change on DCD */ +#define UART_MDMS_DCD_CHG _BIT(3) +/* Bit for detecting state change on RI */ +#define UART_MDMS_RI_CHG _BIT(2) +/* Bit for detecting state change on DSR */ +#define UART_MDMS_DSR_CHG _BIT(1) +/* Bit for detecting state change on CTS */ +#define UART_MDMS_CTS_CHG _BIT(0) + +/********************************************************************** +* rxlev register definitions +**********************************************************************/ +/* Macro for masking off the receive FIFO level */ +#define UART_RXLEVL(n) ((n) & 0x7F) + +/********************************************************************** +* ctrl register definitions +**********************************************************************/ +/* UART3 modem control pin enable bit */ +#define UART_U3_MD_CTRL_EN _BIT(11) +/* IRRX6 inversion enable bit */ +#define UART_IRRX6_INV_EN _BIT(10) +/* IRRX6 RX mask while TX enabled enable bit */ +#define UART_HDPX_EN _BIT(9) +/* UART6 IRA modulator bypass bit */ +#define UART_UART6_IRDAMOD_BYPASS _BIT(5) +/* IRTX6 inversion enable bit */ +#define RT_IRTX6_INV_EN _BIT(4) +/* IRRX6 inversion enable bit */ +#define RT_IRTX6_INV_MIR_EN _BIT(3) +/* IR RX length, 3/16th pulse length with a 115Kbps clock */ +#define RT_RX_IRPULSE_3_16_115K _BIT(2) +/* IR TX length, 3/16th pulse length with a 115Kbps clock */ +#define RT_TX_IRPULSE_3_16_115K _BIT(1) +/* UART5 mirror route to the USB D+ and D- pins bit */ +#define UART_U5_ROUTE_TO_USB _BIT(0) + +/********************************************************************** +* clkmode register definitions +**********************************************************************/ +/* Macro return the UART clock enabled field, shifted */ +#define UART_ENABLED_CLOCKS(n) (((n) >> 16) & 0x7F) +/* Macro returning a selected enabled UART clock bit */ +#define UART_ENABLED_CLOCK(n, u) (((n) >> (16 + (u))) & 0x1) +/* Bit that indicates if any UARTS are being clocked */ +#define UART_ENABLED_CLKS_ANY _BIT(14) +/* Defnies for setting a IARTs clock mode */ +#define UART_CLKMODE_OFF 0x0 /* Clocks are off */ +#define UART_CLKMODE_ON 0x1 /* Clocks are on */ +#define UART_CLKMODE_AUTO 0x2 /* Clocks are automatic */ +/* Clock mode mask for a UART, for UARTs 6 to 3 only */ +#define UART_CLKMODE_MASK(u) (0x3 << ((((u) - 3) * 2) + 4)) +/* Macro for loading a UARTs clock mode, for UARTs 6 to 3 only */ +#define UART_CLKMODE_LOAD(m, u) ((m) << ((((u) - 3) * 2) + 4)) + +/********************************************************************** +* loop register definitions +**********************************************************************/ +/* Marco for getting a specific UART loopback nmode enable bit, for + all UARTs 1 to 7 */ +#define UART_LPBACK_ENABLED(u) (0x1 << ((u) - 1)) + +/* Macros pointing to UART registers */ +#define UART3 ((UART_REGS_T *)(UART3_BASE)) +#define UART4 ((UART_REGS_T *)(UART4_BASE)) +#define UART5 ((UART_REGS_T *)(UART5_BASE)) +#define UART6 ((UART_REGS_T *)(UART6_BASE)) + +#endif /* LPC32XX_STANDARD_UART_H */ diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_usbd.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_usbd.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/lpc32xx_usbd.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/lpc32xx_usbd.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,130 @@ +/* + * asm-arm/arch-lpc32xx/lpc32xx_usbd.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 LPC32XX_USBD_H +#define LPC32XX_USBD_H + +/********************************************************************** +* USE device controller register offsets +**********************************************************************/ + +#define USBD_DEVINTST(x) (x + 0x200) +#define USBD_DEVINTEN(x) (x + 0x204) +#define USBD_DEVINTCLR(x) (x + 0x208) +#define USBD_DEVINTSET(x) (x + 0x20C) +#define USBD_CMDCODE(x) (x + 0x210) +#define USBD_CMDDATA(x) (x + 0x214) +#define USBD_RXDATA(x) (x + 0x218) +#define USBD_TXDATA(x) (x + 0x21C) +#define USBD_RXPLEN(x) (x + 0x220) +#define USBD_TXPLEN(x) (x + 0x224) +#define USBD_CTRL(x) (x + 0x228) +#define USBD_DEVINTPRI(x) (x + 0x22C) +#define USBD_EPINTST(x) (x + 0x230) +#define USBD_EPINTEN(x) (x + 0x234) +#define USBD_EPINTCLR(x) (x + 0x238) +#define USBD_EPINTSET(x) (x + 0x23C) +#define USBD_EPINTPRI(x) (x + 0x240) +#define USBD_REEP(x) (x + 0x244) +#define USBD_EPIND(x) (x + 0x248) +#define USBD_EPMAXPSIZE(x) (x + 0x24C) +#define USBD_DMARST(x) (x + 0x250) +#define USBD_DMARCLR(x) (x + 0x254) +#define USBD_DMARSET(x) (x + 0x258) +#define USBD_UDCAH(x) (x + 0x280) +#define USBD_EPDMAST(x) (x + 0x284) +#define USBD_EPDMAEN(x) (x + 0x288) +#define USBD_EPDMADIS(x) (x + 0x28C) +#define USBD_DMAINTST(x) (x + 0x290) +#define USBD_DMAINTEN(x) (x + 0x294) +#define USBD_EOTINTST(x) (x + 0x2A0) +#define USBD_EOTINTCLR(x) (x + 0x2A4) +#define USBD_EOTINTSET(x) (x + 0x2A8) +#define USBD_NDDRTINTST(x) (x + 0x2AC) +#define USBD_NDDRTINTCLR(x) (x + 0x2B0) +#define USBD_NDDRTINTSET(x) (x + 0x2B4) +#define USBD_SYSERRTINTST(x) (x + 0x2B8) +#define USBD_SYSERRTINTCLR(x) (x + 0x2BC) +#define USBD_SYSERRTINTSET(x) (x + 0x2C0) + +/********************************************************************** +* USBD_DEVINTST/USBD_DEVINTEN/USBD_DEVINTCLR/USBD_DEVINTSET/ +* USBD_DEVINTPRI register definitions +**********************************************************************/ +#define USBD_ERR_INT (1 << 9) +#define USBD_EP_RLZED (1 << 8) +#define USBD_TXENDPKT (1 << 7) +#define USBD_RXENDPKT (1 << 6) +#define USBD_CDFULL (1 << 5) +#define USBD_CCEMPTY (1 << 4) +#define USBD_DEV_STAT (1 << 3) +#define USBD_EP_SLOW (1 << 2) +#define USBD_EP_FAST (1 << 1) +#define USBD_FRAME (1 << 0) + +/********************************************************************** +* USBD_EPINTST/USBD_EPINTEN/USBD_EPINTCLR/USBD_EPINTSET/ +* USBD_EPINTPRI register definitions +**********************************************************************/ +/* End point selection macro (RX) */ +#define USBD_RX_EP_SEL(e) (1 << ((e) << 1)) + +/* End point selection macro (TX) */ +#define USBD_TX_EP_SEL(e) (1 << (((e) << 1) + 1)) + +/********************************************************************** +* USBD_REEP/USBD_DMARST/USBD_DMARCLR/USBD_DMARSET/USBD_EPDMAST/ +* USBD_EPDMAEN/USBD_EPDMADIS/USBD_DMAINTST/USBD_DMAINTEN/ +* USBD_NDDRTINTST/USBD_NDDRTINTCLR/USBD_NDDRTINTSET/ +* USBD_EOTINTST/USBD_EOTINTCLR/USBD_EOTINTSET/ +* USBD_SYSERRTINTST/USBD_SYSERRTINTCLR/USBD_SYSERRTINTSET +* register definitions +**********************************************************************/ +/* Endpoint selection macro */ +#define USBD_EP_SEL(e) (1 << (e)) + +/********************************************************************** +* USBD_RXPLEN register definitions +**********************************************************************/ +#define USBD_PKT_RDY (1 << 11) +#define USBD_DV (1 << 10) +#define USBD_PK_LEN_MASK 0x3FF + +/********************************************************************** +* USBD_CTRL register definitions +**********************************************************************/ +#define USBD_LOG_ENDPOINT(e) ((e) << 2) +#define USBD_WR_EN (1 << 1) +#define USBD_RD_EN (1 << 0) + +/********************************************************************** +* USBD_CMDCODE register definitions +**********************************************************************/ +#define USBD_CMD_CODE(c) ((c) << 16) +#define USBD_CMD_PHASE(p) ((p) << 8) + +/********************************************************************** +* USBD_DMARST/USBD_DMARCLR/USBD_DMARSET register definitions +**********************************************************************/ +#define USBD_DMAEP(e) (1 << (e)) + +#endif /* LPC32XX_USBD_H */ diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/memory.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/memory.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/memory.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/memory.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,34 @@ +/* + * asm-arm/arch-lpc32xx/memory.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +/* + * Physical DRAM offset. + */ +#define PHYS_OFFSET (0x80000000) + +#define __virt_to_bus(x) ((x) - PAGE_OFFSET + PHYS_OFFSET) +#define __bus_to_virt(x) ((x) + PAGE_OFFSET - PHYS_OFFSET) + +#endif diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/platform.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/platform.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/platform.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/platform.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,130 @@ +/* + * asm-arm/arch-lpc32xx/platform.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 __LPC32XX_PLATFORM_H__ +#define __LPC32XX_PLATFORM_H__ + +#include + +/* + * AHB 0 physical base addresses + */ +#define SLC_BASE 0x20020000 +#define SSP0_BASE 0x20084000 +#define SPI1_BASE 0x20088000 +#define SSP1_BASE 0x2008C000 +#define SPI2_BASE 0x20090000 +#define I2S0_BASE 0x20094000 +#define SD_BASE 0x20098000 +#define I2S1_BASE 0x2009C000 +#define MLC_BASE 0x200A8000 +#define AHB0_START SLC_BASE +#define AHB0_SIZE ((MLC_BASE - SLC_BASE) + SZ_4K) + +/* + * AHB 1 physical base addresses + */ +#define DMA_BASE 0x31000000 +#define USB_BASE 0x31020000 +#define USBH_BASE 0x31020000 +#define USB_OTG_BASE 0x31020000 +#define OTG_I2C_BASE 0x31020300 +#define LCD_BASE 0x31040000 +#define ETHERNET_BASE 0x31060000 +#define EMC_BASE 0x31080000 +#define ETB_CFG_BASE 0x310C0000 +#define ETB_DATA_BASE 0x310E0000 +#define AHB1_START DMA_BASE +#define AHB1_SIZE ((EMC_BASE - DMA_BASE) + SZ_4K) + +/* + * FAB physical base addresses + */ +#define CLK_PM_BASE 0x40004000 +#define MIC_BASE 0x40008000 +#define SIC1_BASE 0x4000C000 +#define SIC2_BASE 0x40010000 +#define HS_UART1_BASE 0x40014000 +#define HS_UART2_BASE 0x40018000 +#define HS_UART7_BASE 0x4001C000 +#define RTC_BASE 0x40024000 +#define RTC_RAM_BASE 0x40024080 +#define GPIO_BASE 0x40028000 +#define PWM3_BASE 0x4002C000 +#define PWM4_BASE 0x40030000 +#define MSTIM_BASE 0x40034000 +#define HSTIM_BASE 0x40038000 +#define WDTIM_BASE 0x4003C000 +#define DEBUG_CTRL_BASE 0x40040000 +#define TIMER0_BASE 0x40044000 +#define ADC_BASE 0x40048000 +#define TIMER1_BASE 0x4004C000 +#define KSCAN_BASE 0x40050000 +#define UART_CTRL_BASE 0x40054000 +#define TIMER2_BASE 0x40058000 +#define PWM1_BASE 0x4005C000 +#define PWM2_BASE 0x4005C004 +#define TIMER3_BASE 0x40060000 + +/* + * APB physical base addresses + */ + +#define UART3_BASE 0x40080000 +#define UART4_BASE 0x40088000 +#define UART5_BASE 0x40090000 +#define UART6_BASE 0x40098000 +#define I2C1_BASE 0x400A0000 +#define I2C2_BASE 0x400A8000 + +/* FAB and APB base and sizing */ +#define FABAPB_START CLK_PM_BASE +#define FABAPB_SIZE ((I2C2_BASE - CLK_PM_BASE) + SZ_4K) + +/* + * Internal memory Bases + */ +#define IRAM_BASE 0x08000000 +#define IROM_BASE 0x0C000000 + +/* + * External Static Memory Bank Address Space Bases + */ +#define EMC_CS0_BASE 0xE0000000 +#define EMC_CS1_BASE 0xE1000000 +#define EMC_CS2_BASE 0xE2000000 +#define EMC_CS3_BASE 0xE3000000 + +/* + * External SDRAM Memory Bank Address Space Bases + */ +#define EMC_DYCS0_BASE 0x80000000 +#define EMC_DYCS1_BASE 0xA0000000 + +/* + * Clock and crystal information + */ +#define MAIN_OSC_FREQ 13000000 +#define CLOCK_OSC_FREQ 32768 + +#endif + diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/system.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/system.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/system.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/system.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,40 @@ +/* + * asm-arm/arch-lpc32xx/system.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 __ASM_ARCH_SYSTEM_H +#define __ASM_ARCH_SYSTEM_H + +#include +#include +#include + +static void arch_idle(void) +{ + cpu_do_idle(); +} + +static inline void arch_reset(char mode) +{ + cpu_reset(0); +} + +#endif diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/timex.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/timex.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/timex.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/timex.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,31 @@ +/* + * asm-arm/arch-lpc32xx/timex.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 __LPC32XX_TIMEX_H +#define __LPC32XX_TIMEX_H + +#include + +#define CLOCK_TICK_RATE (MAIN_OSC_FREQ) + +#endif + diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/uncompress.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/uncompress.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/uncompress.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/uncompress.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,47 @@ +/* + * asm-arm/arch-lpc32xx/uncompress.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +/* Access UART with physical addresses before MMU is setup */ +#define UART_DATA (*(volatile unsigned long*) (UART5_BASE + 0x00)) +#define UART_FIFO_CTL (*(volatile unsigned long*) (UART5_BASE + 0x08)) +#define UART_FIFO_CTL_TX_RESET (1 << 2) +#define UART_STATUS (*(volatile unsigned long*) (UART5_BASE + 0x14)) +#define UART_STATUS_TX_MT (1 << 6) + +static inline void putc(int ch) +{ + /* Wait for transmit FIFO to empty */ + while ((UART_STATUS & UART_STATUS_TX_MT) == 0); + + UART_DATA = ch; +} + +static inline void flush(void) +{ + UART_FIFO_CTL |= UART_FIFO_CTL_TX_RESET; +} + + /* NULL functions; we don't presently need them */ +#define arch_decomp_setup() +#define arch_decomp_wdog() diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/vmalloc.h linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/vmalloc.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/include/mach/vmalloc.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/include/mach/vmalloc.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,23 @@ +/* + * asm-arm/arch-lpc32xx/vmalloc.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 + */ + +#define VMALLOC_END (PAGE_OFFSET + 0x10000000) diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/irq-lpc32xx.c linux-2.6.27.8/arch/arm/mach-lpc32xx/irq-lpc32xx.c --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/irq-lpc32xx.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/irq-lpc32xx.c 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,226 @@ +/* + * linux/arch/arm/mach-lpc32xx/irq-lpc32xx.c + * + * Copyright (C) 2008 NXP Semiconductors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void get_controller(unsigned int irq, unsigned int *base, unsigned int *irqbit) +{ + if (irq < 32) { + *base = io_p2v(MIC_BASE); + *irqbit = 1 << irq; + } + else if (irq < 64) { + *base = io_p2v(SIC1_BASE); + *irqbit = 1 << (irq - 32); + } + else { + *base = io_p2v(SIC2_BASE); + *irqbit = 1 << (irq - 64); + } +} + +static void lpc32xx_mask_irq(unsigned int irq) +{ + unsigned int reg, ctrl, mask; + + get_controller(irq, &ctrl, &mask); + + reg = __raw_readl(ctrl + INTC_MASK); + reg &= ~mask; + __raw_writel(reg, (ctrl + INTC_MASK)); +} + +static void lpc32xx_unmask_irq(unsigned int irq) +{ + unsigned int reg, ctrl, mask; + + get_controller(irq, &ctrl, &mask); + + reg = __raw_readl(ctrl + INTC_MASK); + reg |= mask; + __raw_writel(reg, (ctrl + INTC_MASK)); +} + +static void lpc32xx_mask_ack_irq(unsigned int irq) +{ + unsigned int reg, ctrl, mask; + + get_controller(irq, &ctrl, &mask); + + reg = __raw_readl(ctrl + INTC_MASK); + reg &= ~mask; + __raw_writel(reg, (ctrl + INTC_MASK)); + __raw_writel(mask, (ctrl + INTC_RAW_STAT)); +} + +static int lpc32xx_set_irq_type(unsigned int irq, unsigned int type) +{ + unsigned int reg, ctrl, mask; + + get_controller(irq, &ctrl, &mask); + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + /* Rising edge sensitive */ + reg = __raw_readl(ctrl + INTC_POLAR); + reg |= mask; + __raw_writel(reg, (ctrl + INTC_POLAR)); + reg = __raw_readl(ctrl + INTC_ACT_TYPE); + reg |= mask; + __raw_writel(reg, (ctrl + INTC_ACT_TYPE)); + set_irq_handler(irq, handle_edge_irq); + break; + case IRQ_TYPE_EDGE_FALLING: + /* Falling edge sensitive */ + reg = __raw_readl(ctrl + INTC_POLAR); + reg &= ~mask; + __raw_writel(reg, (ctrl + INTC_POLAR)); + reg = __raw_readl(ctrl + INTC_ACT_TYPE); + reg |= mask; + __raw_writel(reg, (ctrl + INTC_ACT_TYPE)); + set_irq_handler(irq, handle_edge_irq); + break; + case IRQ_TYPE_LEVEL_LOW: + /* Low level sensitive */ + reg = __raw_readl(ctrl + INTC_POLAR); + reg &= ~mask; + __raw_writel(reg, (ctrl + INTC_POLAR)); + reg = __raw_readl(ctrl + INTC_ACT_TYPE); + reg &= ~mask; + __raw_writel(reg, (ctrl + INTC_ACT_TYPE)); + set_irq_handler(irq, handle_level_irq); + break; + case IRQ_TYPE_LEVEL_HIGH: + /* High level sensitive */ + reg = __raw_readl(ctrl + INTC_POLAR); + reg |= mask; + __raw_writel(reg, (ctrl + INTC_POLAR)); + reg = __raw_readl(ctrl + INTC_ACT_TYPE); + reg &= ~mask; + __raw_writel(reg, (ctrl + INTC_ACT_TYPE)); + set_irq_handler(irq, handle_level_irq); + break; + + /* IRQT_BOTHEDGE is not supported */ + default: + printk(KERN_ERR "LPC32XX IRQ: Unsupported irq type %d\n", type); + return -1; + } + return 0; +} + +void __init lpc32xx_set_default_mappings(unsigned int base, unsigned int apr, unsigned int atr, unsigned int offset) { + unsigned int i, lvl; + + /* Set activation levels for each interrupt */ + i = 0; + while (i < 32) + { + lvl = ((apr >> i) & 0x1) | (((atr >> i) & 0x1) << 1); + switch (lvl) { + case 0x0: /* Low polarity and level operation */ + lpc32xx_set_irq_type((offset + i), IRQ_TYPE_LEVEL_LOW); + break; + + case 0x1: /* High polarity and level operation */ + lpc32xx_set_irq_type((offset + i), IRQ_TYPE_LEVEL_HIGH); + break; + + case 0x2: /* Low polarity and edge operation */ + lpc32xx_set_irq_type((offset + i), IRQ_TYPE_EDGE_FALLING); + break; + + case 0x3: /* High polarity and edge operation */ + lpc32xx_set_irq_type((offset + i), IRQ_TYPE_EDGE_RISING); + break; + } + + i++; + } +} + +static struct irq_chip lpc32xx_irq_chip = { + .ack = lpc32xx_mask_ack_irq, + .mask = lpc32xx_mask_irq, + .unmask = lpc32xx_unmask_irq, + .set_type = lpc32xx_set_irq_type, +}; + +void __init lpc32xx_init_irq(void) +{ + unsigned int i, vloc; + + /* Setup MIC */ + vloc = io_p2v(MIC_BASE); + __raw_writel(0, (vloc + INTC_MASK)); + __raw_writel(MIC_APR_DEFAULT, (vloc + INTC_POLAR)); + __raw_writel(MIC_ATR_DEFAULT, (vloc + INTC_ACT_TYPE)); + + /* Setup SIC1 */ + vloc = io_p2v(SIC1_BASE); + __raw_writel(0, (vloc + INTC_MASK)); + __raw_writel(SIC1_APR_DEFAULT, (vloc + INTC_POLAR)); + __raw_writel(SIC1_ATR_DEFAULT, (vloc + INTC_ACT_TYPE)); + + /* Setup SIC2 */ + vloc = io_p2v(SIC2_BASE); + __raw_writel(0, (vloc + INTC_MASK)); + __raw_writel(SIC2_APR_DEFAULT, (vloc + INTC_POLAR)); + __raw_writel(SIC2_ATR_DEFAULT, (vloc + INTC_ACT_TYPE)); + + /* Configure supported IRQ's */ + for (i = 0; i < NR_IRQS; i++) { + set_irq_flags(i, IRQF_VALID); + set_irq_chip(i, &lpc32xx_irq_chip); + } + + /* Set default mappings */ + lpc32xx_set_default_mappings(io_p2v(MIC_BASE), MIC_APR_DEFAULT, MIC_ATR_DEFAULT, 0); + lpc32xx_set_default_mappings(io_p2v(SIC1_BASE), SIC1_APR_DEFAULT, SIC1_ATR_DEFAULT, INTC_SIC1_OFFS); + lpc32xx_set_default_mappings(io_p2v(SIC2_BASE), SIC2_APR_DEFAULT, SIC2_ATR_DEFAULT, INTC_SIC2_OFFS); + + /* mask all interrupts except SUBIRQA and SUBFIQ */ + __raw_writel((1 << IRQ_SUB1IRQ) | (1 << IRQ_SUB2IRQ) | + (1 << IRQ_SUB1FIQ) | (1 << IRQ_SUB2FIQ), + (io_p2v(MIC_BASE) + INTC_MASK)); + __raw_writel(0, (io_p2v(SIC1_BASE) + INTC_MASK)); + __raw_writel(0, (io_p2v(SIC2_BASE) + INTC_MASK)); +} + diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/Kconfig linux-2.6.27.8/arch/arm/mach-lpc32xx/Kconfig --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/Kconfig 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/Kconfig 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,174 @@ +if ARCH_LPC32XX + +menu "LPC32XX Implementations" + +config MACH_PHY3250 + bool "Phytec LPC3250 board" + help + Say Y here if you are using the Phytec LPC3250 board. + +config PHY3250_ENABLE_LED_TICK + bool "Enable a 1Hz LED heartbeat tick rate on the Phytec LPC3250 board" + depends on MACH_PHY3250 + default TRUE + help + Say Y here to show the LED heartbeat indicator during the timer tick + +config PHY3250_LCD_PANEL + bool "Enables support for the Phytec LCD" + depends on MACH_PHY3250 + default TRUE + help + Say Y here to enable QVGA panel support + +menu "LCD module revisions - SELECT ONE ONLY" +config PHY3250_QVGA_PANEL_1307_0 + bool "Select the version 1307.0 QVGA panel (RGB565)" + depends on PHY3250_LCD_PANEL + default FALSE + help + Use LCD module version 1307.0 + +config PHY3250_QVGA_PANEL_1307_1 + bool "Select the version 1307.1 QVGA panel (RGB565)" + depends on PHY3250_LCD_PANEL + default TRUE + help + Use LCD module version 1307.1 +endmenu + +menu "CPU module revisions - SELECT ONE ONLY" +config PHY3250_CPU_MODULE_1304_0 + bool "Select the version 1304.0 CPU module" + depends on MACH_PHY3250 + default FALSE + help + Use CPU module version 1304.0 + +config PHY3250_CPU_MODULE_1304_1 + bool "Select the version 1304.1 CPU module" + depends on MACH_PHY3250 + default TRUE + help + Use CPU module version 1304.1 +endmenu + +menu "Carrier board revisions - SELECT ONE ONLY" +config PHY3250_CARRIER_1305_01 + bool "Select the version 1305.0 or 1305.1 carrier board" + depends on MACH_PHY3250 + default FALSE + help + Use carrier board version 1305.0 or 1305.1 + +config PHY3250_CARRIER_1305_2 + bool "Select the version 1305.2 carrier board" + depends on MACH_PHY3250 + default FALSE + help + Use carrier board version 1305.2 + +config PHY3250_CARRIER_1305_3 + bool "Select the version 1305.3 carrier board" + depends on MACH_PHY3250 + default TRUE + help + Use carrier board version 1305.3 +endmenu +endmenu + +menu "LPC32XX chip components" + +config MACH_LPC32XX_IRAM_FOR_CLCD + bool "Use IRAM for the LCD frame buffer" + help + Say Y here to use IRAM for the LCD buffer. + +config MAC_LPC32XX_MII_SUPPORT + bool "Check to enable MII support or leave disabled for RMII support" + default FALSE + help + Say Y here to enable MII support, or N to RMII support. Regardless of + which support is selected, the ethernet interface driver needs to be + selected in the device driver networking section. + +menu "Standard UARTS" + +config MACH_LPC32XX_UART5_ENABLE + bool "Enable UART5" + default TRUE + help + Enables standard UART5 as a TTYSx device + +config MACH_LPC32XX_UART3_ENABLE + bool "Enable UART3" + help + Enables standard UART3 as a TTYSx device + +config MACH_LPC32XX_UART4_ENABLE + bool "Enable UART4" + help + Enables standard UART4 as a TTYSx device + +config MACH_LPC32XX_UART6_ENABLE + bool "Enable UART6" + help + Enables standard UART6 as a TTYSx device + +endmenu + +menu "High speed UARTS" + +config MACH_LPC32XX_HSUART1_ENABLE + bool "Enable high speed UART1" + help + Enables high speed UART1 as a TTYSx device + +config MACH_LPC32XX_HSUART2_ENABLE + bool "Enable high speed UART2" + help + Enables high speed UART2 as a TTYSx device + +config MACH_LPC32XX_HSUART7_ENABLE + bool "Enable high speed UART7" + help + Enables high speed UART7 as a TTYSx device + +endmenu + +menu "I2C interfaces" + +config MACH_LPC32XX_I2C0_ENABLE + bool "Enable I2C0" + help + Enables the I2C0 peripheral + +config MACH_LPC32XX_I2C1_ENABLE + bool "Enable I2C1" + help + Enables the I2C1 peripheral + +config MACH_LPC32XX_USBOTG_I2C_ENABLE + bool "Enable the USB OTG I2C peripheral" + help + Enables the USB OTG I2C peripheral + +endmenu + +menu "SSP/SPI interfaces" + +config MACH_LPC32XX_SSP0_ENABLE + bool "Enable SSP0 for SPI0 mode" + help + Enables the SSP0 peripheral for use as a SPI peripheral + +config MACH_LPC32XX_SSP1_ENABLE + bool "Enable SSP1 for SPI1 mode" + help + Enables the SSP1 peripheral for use as a SPI peripheral + +endmenu +endmenu + +endif + diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/Makefile linux-2.6.27.8/arch/arm/mach-lpc32xx/Makefile --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/Makefile 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/Makefile 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,15 @@ +# +# Makefile for the linux kernel. +# + +# Object file lists. + +obj-y := timer-lpc32xx.o irq-lpc32xx.o arch-lpc32xx.o +obj-y += serial-lpc32xx.o clocks-lpc32xx.o +obj-y += dma-lpc32xx.o +obj-m := +obj-n := +obj- := + +obj-$(CONFIG_MACH_PHY3250) += board-phy3250.o + diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/Makefile.boot linux-2.6.27.8/arch/arm/mach-lpc32xx/Makefile.boot --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/Makefile.boot 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/Makefile.boot 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,4 @@ + zreladdr-y := 0x80008000 +params_phys-y := 0x80000100 +initrd_phys-y := 0x82000000 + diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/serial-lpc32xx.c linux-2.6.27.8/arch/arm/mach-lpc32xx/serial-lpc32xx.c --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/serial-lpc32xx.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/serial-lpc32xx.c 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,217 @@ +/* + * linux/arch/arm/mach-lpc32xx/serial-lpc32xx.c + * + * Copyright (C) 2008 NXP Semiconductors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "sys-lpc32xx.h" + +#define UARTCTL_CLKMODE(x) (x + 0x04) + +/* Standard 8250/16550 compatible serial ports */ +struct plat_serial8250_port serial_std_platform_data[] = +{ +#if defined (CONFIG_MACH_LPC32XX_UART5_ENABLE) + { + .membase = (void *) io_p2v(UART5_BASE), + .mapbase = UART5_BASE, + .irq = IRQ_UART_IIR5, + .uartclk = MAIN_OSC_FREQ, + .regshift = 2, + .iotype = UPIO_MEM32, + .flags = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART | UPF_SKIP_TEST, + }, +#endif +#if defined (CONFIG_MACH_LPC32XX_UART3_ENABLE) + { + .membase = (void *) io_p2v(UART3_BASE), + .mapbase = UART3_BASE, + .irq = IRQ_UART_IIR3, + .uartclk = MAIN_OSC_FREQ, + .regshift = 2, + .iotype = UPIO_MEM32, + .flags = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART | UPF_SKIP_TEST, + }, +#endif +#if defined (CONFIG_MACH_LPC32XX_UART4_ENABLE) + { + .membase = (void *) io_p2v(UART4_BASE), + .mapbase = UART4_BASE, + .irq = IRQ_UART_IIR4, + .uartclk = MAIN_OSC_FREQ, + .regshift = 2, + .iotype = UPIO_MEM32, + .flags = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART | UPF_SKIP_TEST, + }, +#endif +#if defined (CONFIG_MACH_LPC32XX_UART6_ENABLE) + { + .membase = (void *) io_p2v(UART6_BASE), + .mapbase = UART6_BASE, + .irq = IRQ_UART_IIR6, + .uartclk = MAIN_OSC_FREQ, + .regshift = 2, + .iotype = UPIO_MEM32, + .flags = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART | UPF_SKIP_TEST, + }, +#endif + { }, +}; + +struct platform_device serial_std_platform_device = { + .name = "serial8250", + .id = 0, + .dev = { + .platform_data = serial_std_platform_data, + }, +}; + +/* High speed serial ports */ +struct uart_port serial_hspd_platform_data[] = +{ +#if defined (CONFIG_MACH_LPC32XX_HSUART1_ENABLE) + { + .membase = (void *) io_p2v(HS_UART1_BASE), + .mapbase = HS_UART1_BASE, + .irq = IRQ_UART_IIR1, + .uartclk = MAIN_OSC_FREQ, + .regshift = 2, + .iotype = UPIO_MEM32, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, + }, +#endif +#if defined (CONFIG_MACH_LPC32XX_HSUART2_ENABLE) + { + .membase = (void *) io_p2v(HS_UART2_BASE), + .mapbase = HS_UART2_BASE, + .irq = IRQ_UART_IIR2, + .uartclk = MAIN_OSC_FREQ, + .regshift = 2, + .iotype = UPIO_MEM32, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, + }, +#endif +#if defined (CONFIG_MACH_LPC32XX_HSUART7_ENABLE) + { + .membase = (void *) io_p2v(HS_UART7_BASE), + .mapbase = HS_UART7_BASE, + .irq = IRQ_UART_IIR7, + .uartclk = MAIN_OSC_FREQ, + .regshift = 2, + .iotype = UPIO_MEM32, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, + }, +#endif + { }, +}; + +struct platform_device serial_hspd_platform_device = { + .name = "lpc32xx_hsuart", + .id = 0, + .dev = { + .platform_data = serial_hspd_platform_data, + }, +}; + +void serial_init(void) +{ + u32 tmp, rate; + struct clk *clk; + int i; + + /* Get the current peripheral clock rate. This is the base clock for the + UART block and may vary based on selected oscillator or rate */ + clk = clk_get(NULL, "pclk_ck"); + if (IS_ERR(clk)) + { + /* Just use main oscillator rate */ + rate = MAIN_OSC_FREQ; + } + else + { + rate = clk_get_rate(clk); + clk_put(clk); + } + if (rate == 0) + { + rate = MAIN_OSC_FREQ; + } + + /* Update rate for the UART */ + for (i = 0; i < ARRAY_SIZE(serial_std_platform_data); i++) + { + serial_std_platform_data[i].uartclk = rate; + } + for (i = 0; i < ARRAY_SIZE(serial_hspd_platform_data); i++) + { + serial_hspd_platform_data[i].uartclk = rate; + serial_hspd_platform_data[i].line = i; + } + + /* All pre-UART block dividers set to 1 */ + __raw_writel(0x0101, CLKPWR_UART3_CLK_CTRL(CLKPWR_IOBASE)); + __raw_writel(0x0101, CLKPWR_UART4_CLK_CTRL(CLKPWR_IOBASE)); + __raw_writel(0x0101, CLKPWR_UART5_CLK_CTRL(CLKPWR_IOBASE)); + __raw_writel(0x0101, CLKPWR_UART6_CLK_CTRL(CLKPWR_IOBASE)); + + /* Enable UART clocking in clock and power control */ + tmp = 0; +#if defined (CONFIG_MACH_LPC32XX_UART5_ENABLE) + tmp |= CLKPWR_UARTCLKCTRL_UART5_EN; +#endif +#if defined (CONFIG_MACH_LPC32XX_UART3_ENABLE) + tmp |= CLKPWR_UARTCLKCTRL_UART3_EN; +#endif +#if defined (CONFIG_MACH_LPC32XX_UART4_ENABLE) + tmp |= CLKPWR_UARTCLKCTRL_UART4_EN; +#endif +#if defined (CONFIG_MACH_LPC32XX_UART6_ENABLE) + tmp |= CLKPWR_UARTCLKCTRL_UART6_EN; +#endif + __raw_writel(tmp, CLKPWR_UART_CLK_CTRL(CLKPWR_IOBASE)); + + /* Setup UART clock modes, disable autoclock */ + tmp = 0; +#if defined (CONFIG_MACH_LPC32XX_UART5_ENABLE) + tmp |= UART_CLKMODE_LOAD(UART_CLKMODE_ON, 5); +#endif +#if defined (CONFIG_MACH_LPC32XX_UART3_ENABLE) + tmp |= UART_CLKMODE_LOAD(UART_CLKMODE_ON, 3); +#endif +#if defined (CONFIG_MACH_LPC32XX_UART4_ENABLE) + tmp |= UART_CLKMODE_LOAD(UART_CLKMODE_ON, 4); +#endif +#if defined (CONFIG_MACH_LPC32XX_UART6_ENABLE) + tmp |= UART_CLKMODE_LOAD(UART_CLKMODE_ON, 6); +#endif + + /* Enable UART clocks, disable autoclock */ + __raw_writel(tmp, UARTCTL_CLKMODE(io_p2v(UART_CTRL_BASE))); +} + diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/sys-lpc32xx.h linux-2.6.27.8/arch/arm/mach-lpc32xx/sys-lpc32xx.h --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/sys-lpc32xx.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/sys-lpc32xx.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,83 @@ +/* + * linux/arch/arm/mach-lpc32xx/sys-lpc32xx.h + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 __SYS_LPC32XX_H +#define __SYS_PLC32XX_H + +#include +#include +#include +#include + +#include +#include + +#define TIMER0_IOBASE io_p2v(TIMER0_BASE) +#define CLKPWR_IOBASE io_p2v(CLK_PM_BASE) +#define GPIO_IOBASE io_p2v(GPIO_BASE) + +/* + * Board specific data structures + */ +extern struct lpc32XX_kscan_cfg lpc32xx_kscancfg; +extern struct mmc_platform_data lpc32xx_plat_data; +extern struct lpc32XX_nand_cfg lpc32xx_nandcfg; +extern struct clcd_board lpc32xx_clcd_data; +extern struct lpc32xx_net_cfg lpc32xx_netdata; +extern struct lpc32xx_spi_cfg lpc32xx_spi1data; +extern struct lpc32xx_spi_cfg lpc32xx_spi2data; + +/* + * Board specific functions + */ +extern void board_init(void); +#if defined (CONFIG_PHY3250_ENABLE_LED_TICK) +#define LEDTICK { \ + static int blink = 0; \ + static int tick1 = 0; \ + tick1++; \ + if (tick1 > HZ) \ + { \ + tick1 = 0; \ + blink = 1 - blink; \ + if (blink == 0) { \ + __raw_writel(OUTP_STATE_GPO(1), GPIO_P3_OUTP_SET(GPIO_IOBASE)); \ + } \ + else { \ + __raw_writel(OUTP_STATE_GPO(1), GPIO_P3_OUTP_CLR(GPIO_IOBASE)); \ + } \ + } \ +} +#else +#define LEDTICK {} +#endif + +/* Chip specific structures and functions */ +extern struct platform_device serial_std_platform_device; +extern struct platform_device serial_hspd_platform_device; +extern struct sys_timer lpc32xx_timer; +extern void lpc32xx_init_irq (void); +extern void serial_init(void); +extern void __init lpc32xx_init (void); +extern void __init lpc32xx_map_io(void); +extern int __init clk_init(void); + +#endif + diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mach-lpc32xx/timer-lpc32xx.c linux-2.6.27.8/arch/arm/mach-lpc32xx/timer-lpc32xx.c --- linux-2.6.27.8-base/arch/arm/mach-lpc32xx/timer-lpc32xx.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mach-lpc32xx/timer-lpc32xx.c 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,116 @@ +/* + * linux/arch/arm/mach-lpc32xx/timer-lpc32xx.h + * + * Copyright (C) 2008 NXP Semiconductors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include "sys-lpc32xx.h" + +#ifndef LEDTICK +#define LEDTICK +#endif + +extern int clk_is_sysclk_mainosc(void); +extern u32 local_clk_get_pllrate_from_reg(u32 inputclk, u32 regval); +extern u32 clk_get_pclk_div(void); + +static irqreturn_t lpc32xx_timer_interrupt(int irq, void *dev_id) +{ + /* Clear match */ + __raw_writel(TIMER_CNTR_MTCH_BIT(0), TIMER_IR(TIMER0_IOBASE)); + + timer_tick(); + + /* Optional board specific LED function */ + LEDTICK + + return IRQ_HANDLED; +} + +static struct irqaction lpc32xx_timer_irq = { + .name = "LPC32XX Timer Tick", + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .handler = lpc32xx_timer_interrupt, +}; + +static void __init lpc32xx_timer_init (void) +{ + u32 clkrate, pllreg; + + /* Enable timer clock */ + __raw_writel(CLKPWR_TMRPWMCLK_TIMER0_EN, CLKPWR_TIMER_CLK_CTRL(CLKPWR_IOBASE)); + + /* The clock driver isn't initialized at this point. So determine if the SYSCLK + is driven from the PLL397 or main oscillator and then use it to compute + the PLL frequency and the PCLK divider to get the base timer 0 rate */ + if (clk_is_sysclk_mainosc() != 0) + { + clkrate = MAIN_OSC_FREQ; + } + else + { + clkrate = 397 * CLOCK_OSC_FREQ; + } + + /* Get ARM HCLKPLL register and convert it into a frequency*/ + pllreg = __raw_readl(CLKPWR_HCLKPLL_CTRL(CLKPWR_IOBASE)) & 0x1FFFF; + clkrate = local_clk_get_pllrate_from_reg(clkrate, pllreg); + + /* Get PCLK divider and divde ARM PLL clock with it to get timer rate */ + clkrate = clkrate / clk_get_pclk_div(); + + /* Initial timer setup */ + __raw_writel(0, TIMER_TCR(TIMER0_IOBASE)); + __raw_writel(TIMER_CNTR_MTCH_BIT(0), TIMER_IR(TIMER0_IOBASE)); + __raw_writel(1, TIMER_MR0(TIMER0_IOBASE)); + __raw_writel((TIMER_CNTR_MCR_MTCH(0) | TIMER_CNTR_MCR_RESET(0)), TIMER_MCR(TIMER0_IOBASE)); + __raw_writel(0, TIMER_PC(TIMER0_IOBASE)); + __raw_writel(0, TIMER_TC(TIMER0_IOBASE)); + + /* Setup timer for a periodic rate based on HZ */ + __raw_writel((clkrate / (2 * HZ)), TIMER_PR(TIMER0_IOBASE)); + + /* Setup tick interrupt */ + setup_irq (IRQ_TIMER0, &lpc32xx_timer_irq); + + /* Start timer tick */ + __raw_writel(TIMER_CNTR_TCR_EN, TIMER_TCR(TIMER0_IOBASE)); +} + +struct sys_timer lpc32xx_timer = { + .init = &lpc32xx_timer_init, +}; + diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/Makefile linux-2.6.27.8/arch/arm/Makefile --- linux-2.6.27.8-base/arch/arm/Makefile 2009-01-08 11:42:27.000000000 -0800 +++ linux-2.6.27.8/arch/arm/Makefile 2009-01-08 12:02:03.000000000 -0800 @@ -121,6 +121,7 @@ plat-$(CONFIG_ARCH_OMAP) := omap machine-$(CONFIG_ARCH_S3C2410) := s3c2410 s3c2400 s3c2412 s3c2440 s3c2442 s3c2443 plat-$(CONFIG_PLAT_S3C24XX) := s3c24xx + machine-$(CONFIG_ARCH_LPC32XX) := lpc32xx machine-$(CONFIG_ARCH_LH7A40X) := lh7a40x machine-$(CONFIG_ARCH_VERSATILE) := versatile machine-$(CONFIG_ARCH_IMX) := imx diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/arch/arm/mm/Kconfig linux-2.6.27.8/arch/arm/mm/Kconfig --- linux-2.6.27.8-base/arch/arm/mm/Kconfig 2009-01-08 11:42:27.000000000 -0800 +++ linux-2.6.27.8/arch/arm/mm/Kconfig 2009-01-08 12:02:03.000000000 -0800 @@ -187,14 +187,16 @@ ARCH_AT91SAM9260 || ARCH_AT91SAM9261 || \ ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || \ ARCH_AT91SAM9G20 || ARCH_AT91CAP9 || \ - ARCH_NS9XXX || ARCH_DAVINCI || ARCH_MX2 + ARCH_NS9XXX || ARCH_DAVINCI || ARCH_MX2 || \ + ARCH_LPC32XX default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || \ ARCH_OMAP730 || ARCH_OMAP16XX || \ ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || \ ARCH_AT91SAM9260 || ARCH_AT91SAM9261 || \ ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || \ ARCH_AT91SAM9G20 || ARCH_AT91CAP9 || \ - ARCH_NS9XXX || ARCH_DAVINCI || ARCH_MX2 + ARCH_NS9XXX || ARCH_DAVINCI || ARCH_MX2 || \ + ARCH_LPC32XX select CPU_32v5 select CPU_ABRT_EV5TJ select CPU_PABRT_NOIFAR diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/Documentation/arm/LPC32XX/board-phy3250.txt linux-2.6.27.8/Documentation/arm/LPC32XX/board-phy3250.txt --- linux-2.6.27.8-base/Documentation/arm/LPC32XX/board-phy3250.txt 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/Documentation/arm/LPC32XX/board-phy3250.txt 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,35 @@ +The Phytec 3250 board +============================================ + +The Phytec 3250 baord provides a full featured ARM926EJS board based on the +NXP LPC32XX SoC. The board provides support for most interfaces on the SoC +and comes in varying configurations for SDRAM and NAND size. The board is +fully supported by the Linux kernel. + +Bootloader support +============================================ +Currently, u-boot is supported as the Linux bootloader on the PHY3250 board. +The boot process on the PHY3250 board consists on booting a stage 1 loader +from NAND and then loading and starting u-boot. The stage 1 loader does most +of the board configuration including SDRAM and clock setup. More information +on the stage 1 loader (and it's source code and documentation) can be found +included with the Phytec board or available from the NXP website. + +Board specific kernel support +============================================ +The board-phy3250.c file provides the board specific functions needed for +setting up the PHY3250 platform with Linux. The functions provide board +specific support for the chip specific drivers as follows: + Keyboard scanner (key scan map) + SDMMC (power control, insertion status) + NAND support (Write protect control, MTD partitioning) + LCD support (display geomnetry, buffer control, power control) + Ethernet MAC address + SPI (via SSP) chip select control + Support for the PCF8563 RTC and the AT256 serial EEPROm + Miscellaneous system setup + +Kevin Wells +kevin.wells@nxp.com +01-16-2009 + diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/Documentation/arm/LPC32XX/lpc32xx.txt linux-2.6.27.8/Documentation/arm/LPC32XX/lpc32xx.txt --- linux-2.6.27.8-base/Documentation/arm/LPC32XX/lpc32xx.txt 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/Documentation/arm/LPC32XX/lpc32xx.txt 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,144 @@ +The NXP LPC32XX System-on-Chip (SoC) +============================================ + +The LPC32XX SoC Linux kernel release provides a full-featured Linux build +with support for most of the LPC32XX SoC device features. The supported +features are shown below: + ARM 926EJS with varying clock speeds up to 266MHz + Support for external SDRAM/DDR + USB 2.0 full speed host and device with the ISP1301 transceiver + I2S audio with the UDA1380 audio CODEC + SDMMC support (via the PL180 driver) + I2C and SPI (via SSP) support + Support for the 4 standard UARTs and 3 high speed UARTs + MTD support with the NAND SLC FLASH controller + Display (LCD) support (via the PL111 driver) + Touch screen support + Ethernet and PHY support + Keyboard scanner support + 1-second RTC support + Watchdog timer support + Vectored Floating Point support + Power management support + DMA support (used with I2S, SDMMC, and USB device) + +Building the kernel +============================================ + +To build the kernel, make the kernel with the menu configuation utility and +select the LPC32XX target. Select one of the available target boards for the +platform and the desired options for the target board. Select the drivers and +kernel components as necessary for your build. + +The LPC32XX architecture can be selected in the "System Type" submenu from +the kernel configuration menu. Once the "NXP LPC32XX " architecture has been +selected, a specific platform type and configurable platform components are +selected in the "LPC32XX Implementations" submenu. Further chip configurable +components are selected in the "LPC32XX chip components" submenu. + +See the section below called "Kernel driver support" for more information on +configuring the kernel's driver support. + +Kernel driver support +============================================ + +USB 2.0 full speed host +-------------------------------------------- +The LPC32XX USB host driver is based on the PNX4008 driver and uses the +ISP1301 transceiver for the USB PHY. I2C is used to configure and control +the ISP1301 transceiver - make sure I2C support is enabled and the USB OTG +I2C channel is enabled in the configurable chip components. + +USB 2.0 full speed device +-------------------------------------------- +Not supported yet. + +I2S audio with the UDA1380 audio CODE +-------------------------------------------- +I2S audio with the UDA1380 audio CODEC is support on the I2S0 and I2S1 +channels under ALSA. Select the appropriate I2S channel for this support +for this interface. UDA1380 support also requires I2C support. + +SDMMC support (via the PL180 driver) +-------------------------------------------- +SDMMC support (up to 4-bit, 25MHz operation) is provided with the ARM PL180 +driver. To enable this support, enable the ARM AMBA PL180 driver. + +I2C support +-------------------------------------------- +I2C support is provided with the PNX4008 I2C driver. To enable this support, +select the PNX4008 I2C component. Individual I2C channels are enabled in the +configurable chip components. + +SPI (via SSP) support +-------------------------------------------- +SPI support is provided for FIFO based SPI transfers on the SSP0 and SSP1 +channels. Individual SPI channels are enabled in the configurable chip +components. + +4 standard UARTs +-------------------------------------------- +The 8250 driver provides support for the 4 standard UARTs of the LPC32XX. +To enable this support, select the 8250 serial driver. Individual UARTs can +be enabled in the configurable chip components. + +3 high speed UARTs +-------------------------------------------- +The 3 high speed UARTs are also supported. Individual UARTs can be enabled +in the configurable chip components. The high speed UARTs are limited to +8-bit transfer mode with no signalling support, but support baud rates as +high as 921Kbps. + +MTD support with the NAND SLC FLASH controller +-------------------------------------------- +Support for small and large block NAND FLASH devices can be selected by +enabling the LPC32XX NAND component. + +Display (LCD) support (via the PL111 driver) +-------------------------------------------- +Display support is provided by the ARM PL11x LCD driver. To enable support +for the display, select the ARM Amba PL11x driver. + +Touch screen support +-------------------------------------------- +Touch screen support is provided by enabling the LPC32XX touchscreen +component. + +Ethernet and PHY support +-------------------------------------------- +Ethernet support is provided by enabling the LPC32XX ethernet MII component. +A compatible ethernet PHY must also be selected for ethernet to work. MII +or RMII mode is selected in the configurable chip components. + +Keyboard scanner support +-------------------------------------------- +The keyscanner is supported with the LPC32XX keyscanner component. + +1-second RTC support +-------------------------------------------- +The 1-second Real Time Clock is supported by enabling the LPC32XX RTC +component. The RTC will keep correct time as long as it is powered on. + +Watchdog timer support +-------------------------------------------- +WDT support is provided with the PNX4008 WDT driver. To enable this support, +select the PNX4008 WDT component. + +LPC32XX based platforms and platform support +============================================ + +To keep the drivers as platform independent as possible, some of the +drivers require board specific functions developed as part of the board +specific platform. The drivers that require board specific code are: + Keyboard scanner + SDMMC + MTD and MTD partitioning + Display (LCD) controller + Ethernet MAC address + SSP (SPI) CS control + Board specific power management functions + +Kevin Wells +kevin.wells@nxp.com +01-7-2009 + diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/Documentation/arm/LPC32XX/SDRAM linux-2.6.27.8/Documentation/arm/LPC32XX/SDRAM --- linux-2.6.27.8-base/Documentation/arm/LPC32XX/SDRAM 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/Documentation/arm/LPC32XX/SDRAM 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,51 @@ +README on the SDRAM Controller for the LH7a40X +============================================== + +The standard configuration for the SDRAM controller generates a sparse +memory array. The precise layout is determined by the SDRAM chips. A +default kernel configuration assembles the discontiguous memory +regions into separate memory nodes via the NUMA (Non-Uniform Memory +Architecture) facilities. In this default configuration, the kernel +is forgiving about the precise layout. As long as it is given an +accurate picture of available memory by the bootloader the kernel will +execute correctly. + +The SDRC supports a mode where some of the chip select lines are +swapped in order to make SDRAM look like a synchronous ROM. Setting +this bit means that the RAM will present as a contiguous array. Some +programmers prefer this to the discontiguous layout. Be aware that +may be a penalty for this feature where some some configurations of +memory are significantly reduced; i.e. 64MiB of RAM appears as only 32 +MiB. + +There are a couple of configuration options to override the default +behavior. When the SROMLL bit is set and memory appears as a +contiguous array, there is no reason to support NUMA. +CONFIG_LH7A40X_CONTIGMEM disables NUMA support. When physical memory +is discontiguous, the memory tables are organized such that there are +two banks per nodes with a small gap between them. This layout wastes +some kernel memory for page tables representing non-existent memory. +CONFIG_LH7A40X_ONE_BANK_PER_NODE optimizes the node tables such that +there are no gaps. These options control the low level organization +of the memory management tables in ways that may prevent the kernel +from booting or may cause the kernel to allocated excessively large +page tables. Be warned. Only change these options if you know what +you are doing. The default behavior is a reasonable compromise that +will suit all users. + +-- + +A typical 32MiB system with the default configuration options will +find physical memory managed as follows. + + node 0: 0xc0000000 4MiB + 0xc1000000 4MiB + node 1: 0xc4000000 4MiB + 0xc5000000 4MiB + node 2: 0xc8000000 4MiB + 0xc9000000 4MiB + node 3: 0xcc000000 4MiB + 0xcd000000 4MiB + +Setting CONFIG_LH7A40X_ONE_BANK_PER_NODE will put each bank into a +separate node. diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/drivers/i2c/busses/i2c-pnx.c linux-2.6.27.8/drivers/i2c/busses/i2c-pnx.c --- linux-2.6.27.8-base/drivers/i2c/busses/i2c-pnx.c 2009-01-08 11:43:28.000000000 -0800 +++ linux-2.6.27.8/drivers/i2c/busses/i2c-pnx.c 2009-01-08 12:02:03.000000000 -0800 @@ -23,7 +23,14 @@ #include #include +#if defined(CONFIG_ARCH_LPC32XX) +#include +#include +/* Allows better jiffie seperation with slow system clocks */ +#define I2C_PNX_TIMEOUT 100 /* msec */ +#else #define I2C_PNX_TIMEOUT 10 /* msec */ +#endif #define I2C_PNX_SPEED_KHZ 100 #define I2C_PNX_REGION_SIZE 0x100 #define PNX_DEFAULT_FREQ 13 /* MHz */ diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/drivers/i2c/busses/Kconfig linux-2.6.27.8/drivers/i2c/busses/Kconfig --- linux-2.6.27.8-base/drivers/i2c/busses/Kconfig 2009-01-08 11:43:28.000000000 -0800 +++ linux-2.6.27.8/drivers/i2c/busses/Kconfig 2009-01-08 12:02:03.000000000 -0800 @@ -415,7 +415,7 @@ config I2C_PNX tristate "I2C bus support for Philips PNX targets" - depends on ARCH_PNX4008 + depends on ARCH_PNX4008 || ARCH_LPC32XX help This driver supports the Philips IP3204 I2C IP block master and/or slave controller diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/drivers/input/keyboard/Kconfig linux-2.6.27.8/drivers/input/keyboard/Kconfig --- linux-2.6.27.8-base/drivers/input/keyboard/Kconfig 2009-01-08 11:43:32.000000000 -0800 +++ linux-2.6.27.8/drivers/input/keyboard/Kconfig 2009-01-08 12:02:03.000000000 -0800 @@ -323,4 +323,14 @@ To compile this driver as a module, choose M here: the module will be called sh_keysc. + +config KEYBOARD_LPC32XX + tristate "LPC32XX key scanner support" + depends on ARCH_LPC32XX + help + Say Y here if you want to use the LPC32XX keyscanner interface. + + To compile this driver as a module, choose M here: the + module will be called lpc32xx_keys. + endif diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/drivers/input/keyboard/lpc32xx_keys.c linux-2.6.27.8/drivers/input/keyboard/lpc32xx_keys.c --- linux-2.6.27.8-base/drivers/input/keyboard/lpc32xx_keys.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/drivers/input/keyboard/lpc32xx_keys.c 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,263 @@ +/* + * linux/drivers/input/keyboard/lpc32xx-keys.c + * + * Copyright (C) 2008 NXP Semiconductors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +struct lpc32xx_kscan_drv +{ + struct input_dev *input; + struct lpc32XX_kscan_cfg *kscancfg; + struct clk *clk; + void __iomem *kscan_base; + int irq; + u8 lastkeystates[8]; +}; + +static irqreturn_t lpc32xx_kscan_irq(int irq, void *dev_id) +{ + int i, j, scancode, keycode; + u8 key, st; + struct lpc32xx_kscan_drv *kscandat = (struct lpc32xx_kscan_drv *) dev_id; + + for (i = 0; i < kscandat->kscancfg->matrix_sz; i++) + { + key = (u8) __raw_readl((i * 4) + KS_DATA(kscandat->kscan_base)); + if (key != kscandat->lastkeystates[i]) + { + for (j = 0; j < kscandat->kscancfg->matrix_sz; j++) + { + st = key & (1 << j); + if (st != (kscandat->lastkeystates[i] & (1 << j))) + { + /* Key state changed */ + scancode = (int) (j * kscandat->kscancfg->matrix_sz) + i; + keycode = kscandat->kscancfg->keymap[scancode]; + input_report_key(kscandat->input, keycode, (st != 0)); + } + } + + kscandat->lastkeystates[i] = key; + } + } + + /* Clear IRQ */ + __raw_writel(1, KS_IRQ(kscandat->kscan_base)); + + input_sync(kscandat->input); + + return IRQ_HANDLED; +} + +static int __devinit lpc32xx_kscan_probe(struct platform_device *pdev) +{ + struct lpc32xx_kscan_drv *kscandat; + struct resource *res; + int retval, i; + + /* Allocate private driver data */ + kscandat = kzalloc(sizeof(struct lpc32xx_kscan_drv), GFP_KERNEL); + if (unlikely(!kscandat)) + { + return -ENOMEM; + } + + /* Get resources */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + { + retval = -EBUSY; + goto errout; + } + + /* Save IO resources */ + kscandat->kscan_base = ioremap(res->start, res->end - res->start + 1); + if (!kscandat->kscan_base) + { + retval = -EBUSY; + goto errout; + } + + /* Get IRQ resource */ + kscandat->irq = platform_get_irq(pdev, 0); + if ((kscandat->irq < 0) || (kscandat->irq >= NR_IRQS)) + { + retval = -EINVAL; + goto errout; + } + retval = request_irq(kscandat->irq, lpc32xx_kscan_irq, + IRQF_DISABLED, "kscanirq", kscandat); + if (retval < 0) + { + goto errout; + } + + kscandat->input = input_allocate_device(); + if (!kscandat->input) + { + retval = -ENOMEM; + goto err_free_irq; + } + + kscandat->kscancfg = (struct lpc32XX_kscan_cfg *) pdev->dev.platform_data; + platform_set_drvdata(pdev, kscandat); + + /* Setup key input */ + kscandat->input->evbit[0] = BIT_MASK(EV_KEY); + kscandat->input->name = pdev->name; + kscandat->input->phys = "matrix-keys/input0"; + kscandat->input->dev.parent = &pdev->dev; + kscandat->input->id.vendor = 0x0001; + kscandat->input->id.product = 0x0001; + kscandat->input->id.version = 0x0100; + for (i = 0; i < kscandat->kscancfg->matrix_sz; i++) + { + __set_bit(kscandat->kscancfg->keymap[i], kscandat->input->keybit); + } + + input_set_capability(kscandat->input, EV_MSC, MSC_SCAN); + + retval = input_register_device(kscandat->input); + if (retval) + { + goto err_free_irq; + } + + /* Get the key scanner clock */ + kscandat->clk = clk_get(&pdev->dev, "key_ck"); + if (IS_ERR(kscandat->clk)) + { + goto err_free_irq; + } + clk_enable(kscandat->clk); + + /* Configure the key scanner */ + __raw_writel(kscandat->kscancfg->deb_clks, KS_DEB(kscandat->kscan_base)); + __raw_writel(kscandat->kscancfg->scan_delay, KS_SCAN_CTL(kscandat->kscan_base)); + __raw_writel(KSCAN_FTST_USE32K_CLK, KS_FAST_TST(kscandat->kscan_base)); + __raw_writel(kscandat->kscancfg->matrix_sz, KS_MATRIX_DIM(kscandat->kscan_base)); + __raw_writel(1, KS_IRQ(kscandat->kscan_base)); + + return 0; + +err_free_irq: + free_irq(kscandat->irq, pdev); +errout: + if (!kscandat) + { + if (!kscandat->input) + { + input_free_device(kscandat->input); + } + if (!kscandat->kscan_base) + { + iounmap(kscandat->kscan_base); + } + + kfree(kscandat); + } + + return retval; +} + +static int __devexit lpc32xx_kscan_remove(struct platform_device *pdev) +{ + struct lpc32xx_kscan_drv *kscandat = platform_get_drvdata(pdev); + + free_irq(kscandat->irq, pdev); + input_unregister_device(kscandat->input); + clk_put(kscandat->clk); + iounmap(kscandat->kscan_base); + kfree(kscandat); + + return 0; +} + +#ifdef CONFIG_PM +static int lpc32xx_kscan_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct lpc32xx_kscan_drv *kscandat = platform_get_drvdata(pdev); + + /* Clear IRQ and disable clock */ + __raw_writel(1, KS_IRQ(kscandat->kscan_base)); + clk_disable(kscandat->clk); + + return 0; +} + +static int lpc32xx_kscan_resume(struct platform_device *pdev) +{ + struct lpc32xx_kscan_drv *kscandat = platform_get_drvdata(pdev); + + /* Enable clock and clear IRQ */ + clk_enable(kscandat->clk); + __raw_writel(1, KS_IRQ(kscandat->kscan_base)); + + return 0; +} +#else +#define lpc32xx_kscan_suspend NULL +#define lpc32xx_kscan_resume NULL +#endif + +struct platform_driver lpc32xx_kscan_driver = { + .probe = lpc32xx_kscan_probe, + .remove = __devexit_p(lpc32xx_kscan_remove), + .suspend = lpc32xx_kscan_suspend, + .resume = lpc32xx_kscan_resume, + .driver = { + .name = "lpc32xx_keys", + } +}; + +static int __init lpc32xx_kscan_init(void) +{ + return platform_driver_register(&lpc32xx_kscan_driver); +} + +static void __exit lpc32xx_kscan_exit(void) +{ + platform_driver_unregister(&lpc32xx_kscan_driver); +} + +module_init(lpc32xx_kscan_init); +module_exit(lpc32xx_kscan_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kevin Wells "); +MODULE_DESCRIPTION("Key scanner driver for LPC32XX devices"); + diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/drivers/input/keyboard/Makefile linux-2.6.27.8/drivers/input/keyboard/Makefile --- linux-2.6.27.8-base/drivers/input/keyboard/Makefile 2009-01-08 11:43:32.000000000 -0800 +++ linux-2.6.27.8/drivers/input/keyboard/Makefile 2009-01-08 12:02:03.000000000 -0800 @@ -27,3 +27,4 @@ obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o +obj-$(CONFIG_KEYBOARD_LPC32XX) += lpc32xx_keys.o diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/drivers/input/touchscreen/Kconfig linux-2.6.27.8/drivers/input/touchscreen/Kconfig --- linux-2.6.27.8-base/drivers/input/touchscreen/Kconfig 2009-01-08 11:43:32.000000000 -0800 +++ linux-2.6.27.8/drivers/input/touchscreen/Kconfig 2009-01-08 12:02:03.000000000 -0800 @@ -282,6 +282,16 @@ To compile this driver as a module, choose M here: the module will be called mainstone-wm97xx. +config TOUCHSCREEN_LPC32XX + tristate "LPC32XX touchscreen controller" + depends on ARCH_LPC32XX + help + Say Y here if you have a LPC32XX device and want + to support the built-in touchscreen. + + To compile this driver as a module, choose M here: the + module will be called lpc32xx_ts. + config TOUCHSCREEN_USB_COMPOSITE tristate "USB Touchscreen Driver" depends on USB_ARCH_HAS_HCD diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/drivers/input/touchscreen/lpc32xx_ts.c linux-2.6.27.8/drivers/input/touchscreen/lpc32xx_ts.c --- linux-2.6.27.8-base/drivers/input/touchscreen/lpc32xx_ts.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/drivers/input/touchscreen/lpc32xx_ts.c 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,322 @@ +/* + * drivers/input/touchscreen/lpc32xx_tsc.c + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#define MOD_NAME "lpc32xx-ts" + +struct lpc32xx_tsc_t +{ + struct input_dev *dev; + void __iomem *tsc_base; + int irq; + struct clk *clk; +}; + +static void lpc32xx_fifo_clear(struct lpc32xx_tsc_t *lpc32xx_tsc_dat) +{ + volatile u32 tmp; + + while (!(__raw_readl(TSC_STAT(lpc32xx_tsc_dat->tsc_base)) & TSC_STAT_FIFO_EMPTY)) + { + tmp = __raw_readl(TSC_FIFO(lpc32xx_tsc_dat->tsc_base)); + } +} + +static irqreturn_t lpc32xx_ts_interrupt(int irq, void *dev_id) +{ + u32 tmp, rv [16], xs [16], ys [16]; + int idx; + struct lpc32xx_tsc_t *lpc32xx_tsc_dat = (struct lpc32xx_tsc_t *) dev_id; + struct input_dev *input = lpc32xx_tsc_dat->dev; + + /* Get the touch status */ + tmp = __raw_readl(TSC_STAT(lpc32xx_tsc_dat->tsc_base)); + + /* FIFO overflow - throw away samples */ + if (tmp & TSC_STAT_FIFO_OVRRN) + { + lpc32xx_fifo_clear(lpc32xx_tsc_dat); + return IRQ_HANDLED; + } + + /* Get samples from FIFO */ + idx = 0; + while ((idx < 4) && + (!(__raw_readl(TSC_STAT(lpc32xx_tsc_dat->tsc_base)) & + TSC_STAT_FIFO_EMPTY))) + { + tmp = __raw_readl(TSC_FIFO(lpc32xx_tsc_dat->tsc_base)); + xs [idx] = TSC_FIFO_NORMALIZE_X_VAL(tmp); + ys [idx] = TSC_FIFO_NORMALIZE_Y_VAL(tmp); + rv [idx] = tmp; + idx++; + } + + /* Data is only valid if pen is still down */ + if ((!(rv [3] & TSC_FIFO_TS_P_LEVEL)) && (idx == 4)) + { + input_report_key(input, BTN_TOUCH, 1); + input_report_abs(input, ABS_X, ((xs [1] + xs [2]) / 2)); + input_report_abs(input, ABS_Y, ((ys [1] + ys [2]) / 2)); + } + else + { + input_report_key(input, BTN_TOUCH, 0); + } + + input_sync(input); + + return IRQ_HANDLED; +} + +static void stop_tsc(struct lpc32xx_tsc_t *lpc32xx_tsc_dat) +{ + u32 tmp; + + /* Disable auto mode */ + tmp = __raw_readl(TSC_CON(lpc32xx_tsc_dat->tsc_base)); + tmp &= ~TSC_ADCCON_AUTO_EN; + __raw_writel(tmp, TSC_CON(lpc32xx_tsc_dat->tsc_base)); +} + +static void setup_tsc(struct lpc32xx_tsc_t *lpc32xx_tsc_dat) +{ + u32 tmp; + + /* Power down ADC */ + tmp = __raw_readl(TSC_CON(lpc32xx_tsc_dat->tsc_base)); + tmp &= ~TSC_ADCCON_POWER_UP; + __raw_writel(tmp, TSC_CON(lpc32xx_tsc_dat->tsc_base)); + + /* Set the TSC FIFO depth to 4 samples @ 10-bits sample */ + tmp = (TSC_ADCCON_IRQ_TO_FIFO_4 | TSC_ADCCON_X_SAMPLE_SIZE(10) | + TSC_ADCCON_Y_SAMPLE_SIZE(10)); + __raw_writel(tmp, TSC_CON(lpc32xx_tsc_dat->tsc_base)); + + /* Set SEL to default value */ + __raw_writel(0x0284, TSC_SEL(lpc32xx_tsc_dat->tsc_base)); + + /* Min/max and aux settings */ + __raw_writel(0x0000, TSC_MIN_X(lpc32xx_tsc_dat->tsc_base)); + __raw_writel(0x03FF, TSC_MAX_X(lpc32xx_tsc_dat->tsc_base)); + __raw_writel(0x0000, TSC_MIN_Y(lpc32xx_tsc_dat->tsc_base)); + __raw_writel(0x03FF, TSC_MAX_Y(lpc32xx_tsc_dat->tsc_base)); + __raw_writel(0x0000, TSC_AUX_UTR(lpc32xx_tsc_dat->tsc_base)); + __raw_writel(0x0000, TSC_AUX_MIN(lpc32xx_tsc_dat->tsc_base)); + __raw_writel(0x0000, TSC_AUX_MAX(lpc32xx_tsc_dat->tsc_base)); + + /* Rise, update, delay, touch, drain X times */ + __raw_writel(TSC_RTR_RISE_TIME(0x2), TSC_RTR(lpc32xx_tsc_dat->tsc_base)); + __raw_writel(TSC_UTR_UPDATE_TIME(446), TSC_UTR(lpc32xx_tsc_dat->tsc_base)); + __raw_writel(TSC_DTR_DELAY_TIME(0x2), TSC_DTR(lpc32xx_tsc_dat->tsc_base)); + __raw_writel(TSC_TTR_TOUCH_TIME(0x10), TSC_TTR(lpc32xx_tsc_dat->tsc_base)); + __raw_writel(TSC_DXP_DRAINX_TIME(0x4), TSC_DXP(lpc32xx_tsc_dat->tsc_base)); + + /* Set sample rate to about 60Hz, this rate is based on the + RTC clock, which should be a stable 32768Hz */ + __raw_writel(TSC_UTR_UPDATE_TIME(88), TSC_UTR(lpc32xx_tsc_dat->tsc_base)); + + /* Empty the touchscreen FIFO */ + lpc32xx_fifo_clear(lpc32xx_tsc_dat); + + /* Enable auto mode */ + tmp = __raw_readl(TSC_CON(lpc32xx_tsc_dat->tsc_base)); + tmp |= TSC_ADCCON_AUTO_EN; + __raw_writel(tmp, TSC_CON(lpc32xx_tsc_dat->tsc_base)); +} + +static int __devinit lpc32xx_ts_probe(struct platform_device *pdev) +{ + struct lpc32xx_tsc_t *lpc32xx_tsc_dat = NULL; + struct resource *res; + int retval = -ENODEV; + + /* Get resources */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + { + retval = -EBUSY; + goto errout; + } + + /* Allocate private driver data */ + lpc32xx_tsc_dat = kzalloc(sizeof(struct lpc32xx_tsc_t), GFP_KERNEL); + if (unlikely(!lpc32xx_tsc_dat)) + { + retval = -ENOMEM; + goto errout; + } + + /* Map IO resources */ + lpc32xx_tsc_dat->tsc_base = ioremap(res->start, res->end - res->start + 1); + if (!lpc32xx_tsc_dat->tsc_base) + { + retval = -EBUSY; + goto errout; + } + + lpc32xx_tsc_dat->dev = input_allocate_device(); + if (!lpc32xx_tsc_dat->dev) + { + retval = -ENOMEM; + goto errout; + } + + /* Enable clock */ + lpc32xx_tsc_dat->clk = clk_get(&pdev->dev, "tsc_ck"); + if (IS_ERR(lpc32xx_tsc_dat->clk)) + { + goto errout; + } + clk_enable(lpc32xx_tsc_dat->clk); + + /* Initially setup TSC */ + setup_tsc(lpc32xx_tsc_dat); + + /* Get interrupt */ + lpc32xx_tsc_dat->irq = platform_get_irq(pdev, 0); + if ((lpc32xx_tsc_dat->irq < 0) || (lpc32xx_tsc_dat->irq >= NR_IRQS)) + { + retval = -EINVAL; + goto errout; + } + + retval = request_irq(lpc32xx_tsc_dat->irq, lpc32xx_ts_interrupt, + 0, MOD_NAME, lpc32xx_tsc_dat); + if (retval < 0) + { + goto err_free_irq; + } + + platform_set_drvdata(pdev, lpc32xx_tsc_dat); + + /* Setup TS driver */ + lpc32xx_tsc_dat->dev->name = "LPC32xx Touchscreen"; + lpc32xx_tsc_dat->dev->phys = "lpc32xx/input0"; + lpc32xx_tsc_dat->dev->id.bustype = BUS_HOST; + lpc32xx_tsc_dat->dev->id.vendor = 0x0001; + lpc32xx_tsc_dat->dev->id.product = 0x0002; + lpc32xx_tsc_dat->dev->id.version = 0x0100; + lpc32xx_tsc_dat->dev->dev.parent = &pdev->dev; + + lpc32xx_tsc_dat->dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + lpc32xx_tsc_dat->dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + input_set_abs_params(lpc32xx_tsc_dat->dev, ABS_X, 0, 1023, 0, 0); + input_set_abs_params(lpc32xx_tsc_dat->dev, ABS_Y, 0, 1023, 0, 0); + + retval = input_register_device(lpc32xx_tsc_dat->dev); + if (retval) + goto err_free_irq; + + return 0; + +err_free_irq: + stop_tsc(lpc32xx_tsc_dat); + platform_set_drvdata(pdev, NULL); + free_irq(lpc32xx_tsc_dat->irq, lpc32xx_tsc_dat->dev); + +errout: + if (lpc32xx_tsc_dat) + { + if (lpc32xx_tsc_dat->clk) + { + clk_disable(lpc32xx_tsc_dat->clk); + clk_put(lpc32xx_tsc_dat->clk); + } + + if (lpc32xx_tsc_dat->dev) + { + input_free_device(lpc32xx_tsc_dat->dev); + } + + if (lpc32xx_tsc_dat->tsc_base) + { + iounmap(lpc32xx_tsc_dat->tsc_base); + } + + kfree(lpc32xx_tsc_dat); + } + + return retval; +} + +static int __devexit lpc32xx_ts_remove(struct platform_device *pdev) +{ + struct lpc32xx_tsc_t *lpc32xx_tsc_dat = platform_get_drvdata(pdev); + + stop_tsc(lpc32xx_tsc_dat); + free_irq(lpc32xx_tsc_dat->irq, lpc32xx_tsc_dat->dev); + platform_set_drvdata(pdev, NULL); + input_unregister_device(lpc32xx_tsc_dat->dev); + + if (lpc32xx_tsc_dat->clk) + { + clk_disable(lpc32xx_tsc_dat->clk); + clk_put(lpc32xx_tsc_dat->clk); + } + + if (lpc32xx_tsc_dat->tsc_base) + { + iounmap(lpc32xx_tsc_dat->tsc_base); + } + kfree(lpc32xx_tsc_dat); + + return 0; +} + +static struct platform_driver lpc32xx_ts_driver = { + .probe = lpc32xx_ts_probe, + .remove = __devexit_p(lpc32xx_ts_remove), + .driver = { + .name = MOD_NAME, + }, +}; + +static int __init lpc32xx_ts_init(void) +{ + return platform_driver_register(&lpc32xx_ts_driver); +} + +static void __exit lpc32xx_ts_exit(void) +{ + platform_driver_unregister(&lpc32xx_ts_driver); +} + +module_init(lpc32xx_ts_init); +module_exit(lpc32xx_ts_exit); + +MODULE_AUTHOR("Kevin Wells #include #include +#if defined (CONFIG_ARCH_LPC32XX) +#include +#endif #include #include @@ -28,6 +31,13 @@ #include #include +#if defined (CONFIG_ARCH_LPC32XX) +#include +#include +#include +#include +#endif + #include "mmci.h" #define DRIVER_NAME "mmci-pl18x" @@ -35,7 +45,136 @@ #define DBG(host,fmt,args...) \ pr_debug("%s: %s: " fmt, mmc_hostname(host->mmc), __func__ , args) +#if defined (CONFIG_ARCH_LPC32XX) +static unsigned int fmax = 26000000; /* 26MHz bit rate max */ + +#define DMA_BUFF_SIZE SZ_64K +static void *dma_p_base, *dma_v_base; +static struct dma_config dmacfgrx, dmacfgtx; +static int lastch = DMA_CH_SDCARD_TX; + +#define MCI_WIDEBUS (1 << 11) +#undef MCI_IRQENABLE +#define MCI_IRQENABLE \ + (MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK| \ + MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \ + MCI_CMDRESPENDMASK|MCI_CMDSENTMASK) + +#else static unsigned int fmax = 515633; +#endif + +#if defined (CONFIG_ARCH_LPC32XX) +static int mmc_dma_setup(void) +{ + /* Setup TX DMA channel */ + dmacfgtx.ch = DMA_CH_SDCARD_TX; + dmacfgtx.tc_inten = 0; + dmacfgtx.err_inten = 0; + dmacfgtx.src_size = 4; + dmacfgtx.src_inc = 1; + dmacfgtx.src_ahb1 = 0; + dmacfgtx.src_bsize = DMAC_CHAN_SRC_BURST_8; + dmacfgtx.src_prph = DMAC_SRC_PERIP(DMA_PERID_SDCARD); + dmacfgtx.dst_size = 4; + dmacfgtx.dst_inc = 0; + dmacfgtx.dst_ahb1 = 0; + dmacfgtx.dst_bsize = DMAC_CHAN_DEST_BURST_8; + dmacfgtx.dst_prph = DMAC_DEST_PERIP(DMA_PERID_SDCARD); + dmacfgtx.flowctrl = DMAC_CHAN_FLOW_P_M2P; + if (lpc32xx_dma_ch_get(&dmacfgtx, "dma_sd_tx", NULL, NULL) < 0) + { + printk(KERN_ERR "Error setting up SD card TX DMA channel\n"); + return -ENODEV; + } + + /* Setup RX DMA channel */ + dmacfgrx.ch = DMA_CH_SDCARD_RX; + dmacfgrx.tc_inten = 0; + dmacfgrx.err_inten = 0; + dmacfgrx.src_size = 4; + dmacfgrx.src_inc = 0; + dmacfgrx.src_ahb1 = 0; + dmacfgrx.src_bsize = DMAC_CHAN_SRC_BURST_8; + dmacfgrx.src_prph = DMAC_SRC_PERIP(DMA_PERID_SDCARD); + dmacfgrx.dst_size = 4; + dmacfgrx.dst_inc = 1; + dmacfgrx.dst_ahb1 = 0; + dmacfgrx.dst_bsize = DMAC_CHAN_DEST_BURST_8; + dmacfgrx.dst_prph = DMAC_DEST_PERIP(DMA_PERID_SDCARD); + dmacfgrx.flowctrl = DMAC_CHAN_FLOW_P_P2M; + if (lpc32xx_dma_ch_get(&dmacfgrx, "dma_sd_rx", NULL, NULL) < 0) + { + printk(KERN_ERR "Error setting up SD card RX DMA channel\n"); + return -ENODEV; + } + + return 0; +} + +static void mmc_dma_start(int ch) +{ + if (ch == DMA_CH_SDCARD_TX) + { + lpc32xx_dma_start_pflow_xfer(DMA_CH_SDCARD_TX, + dma_p_base, (void *) SD_FIFO(SD_BASE), 1); + } + else + { + lpc32xx_dma_start_pflow_xfer(DMA_CH_SDCARD_RX, + (void *) SD_FIFO(SD_BASE), dma_p_base, 1); + } +} + +static void mmc_dma_stop(int ch) +{ + lpc32xx_dma_ch_disable(ch); +} + +static void mmc_tx_dma_copy(struct mmci_host *host) +{ + char *src_buffer, *dst_buffer; + unsigned long flags; + + dst_buffer = (char *) dma_v_base; + do + { + /* + * Map the current scatter buffer, copy data, and unmap + */ + src_buffer = mmci_kmap_atomic(host, &flags) + host->sg_off; + memcpy(dst_buffer, src_buffer, host->sg_ptr->length); + dst_buffer += host->sg_ptr->length; + mmci_kunmap_atomic(host, src_buffer, &flags); + + if (!mmci_next_sg(host)) + break; + } while (1); +} + +static void mmc_dma_rx_copy(struct mmci_host *host) +{ + char *src_buffer, *dst_buffer; + unsigned long flags; + + src_buffer = (char *) dma_v_base; + do + { + /* + * Map the current scatter buffer, copy data, and unmap + */ + dst_buffer = mmci_kmap_atomic(host, &flags) + host->sg_off; + memcpy(dst_buffer, src_buffer, host->sg_ptr->length); + src_buffer += host->sg_ptr->length; + mmci_kunmap_atomic(host, dst_buffer, &flags); + + flush_dcache_page(sg_page(host->sg_ptr)); + + if (!mmci_next_sg(host)) + break; + } while (1); +} +#endif static void mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) @@ -64,11 +203,12 @@ writel(0, host->base + MMCIDATACTRL); writel(0, host->base + MMCIMASK1); host->data = NULL; + mmc_dma_stop(lastch); } static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) { - unsigned int datactrl, timeout, irqmask; + unsigned int datactrl, timeout, irqmask = 0; unsigned long long clks; void __iomem *base; int blksz_bits; @@ -89,6 +229,28 @@ base = host->base; writel(timeout, base + MMCIDATATIMER); +#if defined (CONFIG_ARCH_LPC32XX) + writel((host->size * data->blocks), base + MMCIDATALENGTH); + + blksz_bits = ffs(data->blksz) - 1; + BUG_ON(1 << blksz_bits != data->blksz); + + datactrl = MCI_DPSM_ENABLE | MCI_DPSM_DMAENABLE | blksz_bits << 4; + if (data->flags & MMC_DATA_READ) { + datactrl |= MCI_DPSM_DIRECTION; + lastch = DMA_CH_SDCARD_RX; + } else { + /* Copy data buffer to DMA buffer and start transfer */ + lastch = DMA_CH_SDCARD_TX; + mmc_tx_dma_copy(host); + } + mmc_dma_start(lastch); + + writel(datactrl, base + MMCIDATACTRL); + datactrl = readl(base + MMCIMASK0) & ~MCI_DATABLOCKENDMASK; + writel(datactrl | MCI_DATAENDMASK, base + MMCIMASK0); + +#else writel(host->size, base + MMCIDATALENGTH); blksz_bits = ffs(data->blksz) - 1; @@ -115,6 +277,7 @@ writel(datactrl, base + MMCIDATACTRL); writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0); +#endif writel(irqmask, base + MMCIMASK1); } @@ -150,8 +313,13 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, unsigned int status) { +#if defined (CONFIG_ARCH_LPC32XX) + if (status & MCI_DATAEND) { + host->data_xfered += data->blksz * data->blocks; +#else if (status & MCI_DATABLOCKEND) { host->data_xfered += data->blksz; +#endif } if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) { if (status & MCI_DATACRCFAIL) @@ -162,16 +330,26 @@ data->error = -EIO; status |= MCI_DATAEND; +#if !defined (CONFIG_ARCH_LPC32XX) /* * We hit an error condition. Ensure that any data * partially written to a page is properly coherent. */ if (host->sg_len && data->flags & MMC_DATA_READ) flush_dcache_page(sg_page(host->sg_ptr)); +#endif } if (status & MCI_DATAEND) { mmci_stop_data(host); +#if defined (CONFIG_ARCH_LPC32XX) + /* Copy DMA buffer to MMC buffer */ + if (lastch == DMA_CH_SDCARD_RX) + { + /* Copy DMA buffer to data buffer */ + mmc_dma_rx_copy(host); + } +#endif if (!data->stop) { mmci_request_end(host, data->mrq); } else { @@ -367,7 +545,12 @@ status = readl(host->base + MMCISTATUS); status &= readl(host->base + MMCIMASK0); + +#if defined (CONFIG_ARCH_LPC32XX) + writel((status | MCI_DATABLOCKEND), host->base + MMCICLEAR); +#else writel(status, host->base + MMCICLEAR); +#endif DBG(host, "irq0 %08x\n", status); @@ -449,6 +632,17 @@ if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) pwr |= MCI_ROD; +#if defined (CONFIG_ARCH_LPC32XX) + if (ios->bus_width == MMC_BUS_WIDTH_4 ) + { + clk |= MCI_WIDEBUS; + } + else + { + clk &= ~MCI_WIDEBUS; + } +#endif + writel(clk, host->base + MMCICLOCK); if (host->pwr != pwr) { @@ -481,6 +675,9 @@ struct mmci_host *host; struct mmc_host *mmc; int ret; +#if defined (CONFIG_ARCH_LPC32XX) + dma_addr_t dma_handle; +#endif /* must have platform data */ if (!plat) { @@ -488,9 +685,29 @@ goto out; } +#if defined (CONFIG_ARCH_LPC32XX) + /* Allocate a chunk of memory for the DMA buffers */ + dma_v_base = dma_alloc_coherent(&dev->dev, DMA_BUFF_SIZE, + &dma_handle, GFP_KERNEL); + if (dma_v_base == NULL) + { + printk("%s: error getting DMA region.\n", DRIVER_NAME); + ret = -ENOMEM; + goto out; + } + dma_p_base = (void *) dma_handle; + printk(KERN_INFO "%s: DMA buffer(%x bytes), P:0x%08x, V:0x%08x\n", + DRIVER_NAME, DMA_BUFF_SIZE, (u32) dma_p_base, (u32) dma_v_base); +#endif + ret = amba_request_regions(dev, DRIVER_NAME); - if (ret) + if (ret) { +#if defined (CONFIG_ARCH_LPC32XX) + goto out_free_dma; +#else goto out; +#endif + } mmc = mmc_alloc_host(sizeof(struct mmci_host), &dev->dev); if (!mmc) { @@ -535,6 +752,9 @@ mmc->f_min = (host->mclk + 511) / 512; mmc->f_max = min(host->mclk, fmax); mmc->ocr_avail = plat->ocr_mask; +#if defined (CONFIG_ARCH_LPC32XX) + mmc->caps |= MMC_CAP_4_BIT_DATA; +#endif /* * We can do SGIO @@ -564,6 +784,13 @@ */ mmc->max_blk_count = mmc->max_req_size; +#if defined (CONFIG_ARCH_LPC32XX) + /* + * Setup DMA for the interface + */ + mmc_dma_setup(); +#endif + spin_lock_init(&host->lock); writel(0, host->base + MMCIMASK0); @@ -578,7 +805,11 @@ if (ret) goto irq0_free; +#if defined (CONFIG_ARCH_LPC32XX) + writel(MCI_IRQENABLE|MCI_DATAENDMASK, host->base + MMCIMASK0); +#else writel(MCI_IRQENABLE, host->base + MMCIMASK0); +#endif amba_set_drvdata(dev, mmc); @@ -608,6 +839,11 @@ mmc_free_host(mmc); rel_regions: amba_release_regions(dev); +#if defined (CONFIG_ARCH_LPC32XX) + out_free_dma: + dma_free_coherent(&dev->dev, DMA_BUFF_SIZE, + dma_v_base, (dma_addr_t) dma_p_base); +#endif out: return ret; } @@ -641,6 +877,11 @@ mmc_free_host(mmc); amba_release_regions(dev); + +#if defined (CONFIG_ARCH_LPC32XX) + dma_free_coherent(&dev->dev, DMA_BUFF_SIZE, + dma_v_base, (dma_addr_t) dma_p_base); +#endif } return 0; diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/drivers/mtd/nand/Kconfig linux-2.6.27.8/drivers/mtd/nand/Kconfig --- linux-2.6.27.8-base/drivers/mtd/nand/Kconfig 2009-01-08 11:43:30.000000000 -0800 +++ linux-2.6.27.8/drivers/mtd/nand/Kconfig 2009-01-08 12:02:03.000000000 -0800 @@ -340,6 +340,13 @@ This enables the driver for the NAND flash device found on PXA3xx processors +config MTD_NAND_SLC_LPC32XX + bool "Support for NAND Flash om the LPC32XX" + depends on ARCH_LPC32XX + help + Enables support for NAND Flash using the LPC32XX SLC NAND + controller. + config MTD_NAND_CM_X270 tristate "Support for NAND Flash on CM-X270 modules" depends on MTD_NAND && MACH_ARMCORE diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/drivers/mtd/nand/lpc32xx_nand.c linux-2.6.27.8/drivers/mtd/nand/lpc32xx_nand.c --- linux-2.6.27.8-base/drivers/mtd/nand/lpc32xx_nand.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/drivers/mtd/nand/lpc32xx_nand.c 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,413 @@ +/* + * drivers/mtd/nand/lpc32xx_nand.c + * + * Copyright (C) 2008 NXP Semiconductors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +struct lpc32xx_nand_host { + struct nand_chip nand_chip; + struct clk *clk; + struct mtd_info mtd; + void __iomem *io_base; + struct lpc32XX_nand_cfg *ncfg; +}; + +static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host) +{ + u32 clkrate, tmp; + + /* Reset SLC controller */ + __raw_writel(SLCCTRL_SW_RESET, SLC_CTRL(host->io_base)); + udelay(1000); + + /* Basic setup */ + __raw_writel(0, SLC_CFG(host->io_base)); + __raw_writel(0, SLC_IEN(host->io_base)); + __raw_writel((SLCSTAT_INT_TC | SLCSTAT_INT_RDY_EN), SLC_ICR(host->io_base)); + + /* Get base clock for SLC block */ + clkrate = clk_get_rate(host->clk); + if (clkrate == 0) + { + clkrate = 104000000; + } + + /* Compute clock setup values */ + tmp = SLCTAC_WDR(host->ncfg->wdr_clks) | + SLCTAC_WWIDTH(1 + (clkrate / host->ncfg->wwidth)) | + SLCTAC_WHOLD(1 + (clkrate / host->ncfg->whold)) | + SLCTAC_WSETUP(1 + (clkrate / host->ncfg->wsetup)) | + SLCTAC_RDR(host->ncfg->rdr_clks) | + SLCTAC_RWIDTH(1 + (clkrate / host->ncfg->rwidth)) | + SLCTAC_RHOLD(1 + (clkrate / host->ncfg->rhold)) | + SLCTAC_RSETUP(1 + (clkrate / host->ncfg->rsetup)); + __raw_writel(tmp, SLC_TAC(host->io_base)); +} + +/* + * Hardware specific access to control lines + */ +static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) +{ + u32 tmp; + struct nand_chip *nand_chip = mtd->priv; + struct lpc32xx_nand_host *host = nand_chip->priv; + + /* Does CE state need to be changed? */ + tmp = __raw_readl(SLC_CFG(host->io_base)); + if (ctrl & NAND_NCE) + { + tmp |= SLCCFG_CE_LOW; + } + else + { + tmp &= ~SLCCFG_CE_LOW; + } + __raw_writel(tmp, SLC_CFG(host->io_base)); + + if (cmd != NAND_CMD_NONE) + { + if (ctrl & NAND_CLE) + { + __raw_writel(cmd, SLC_CMD(host->io_base)); + } + else + { + __raw_writel(cmd, SLC_ADDR(host->io_base)); + } + } +} + +/* + * Read the Device Ready pin. + */ +static int lpc32xx_nand_device_ready(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = mtd->priv; + struct lpc32xx_nand_host *host = nand_chip->priv; + int rdy = 0; + + if ((__raw_readl(SLC_STAT(host->io_base)) & SLCSTAT_NAND_READY) != 0) + { + rdy = 1; + } + + return rdy; +} + +/* + * Enable NAND write protect + */ +static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host) +{ + if (host->ncfg->enable_write_prot != NULL) + { + /* Disable write protection */ + host->ncfg->enable_write_prot(1); + } +} + +/* + * Disable NAND write protect + */ +static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host) +{ + if (host->ncfg->enable_write_prot != NULL) + { + /* Enable write protection */ + host->ncfg->enable_write_prot(0); + } +} + +static uint8_t lpc32xx_read_byte(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = mtd->priv; + struct lpc32xx_nand_host *host = nand_chip->priv; + + return (uint8_t) __raw_readl(SLC_DATA(host->io_base)); +} + +static void lpc32xx_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + struct nand_chip *nand_chip = mtd->priv; + struct lpc32xx_nand_host *host = nand_chip->priv; + int i; + + for (i = 0; i < len; i++) + { + buf[i] = (uint8_t) __raw_readl(SLC_DATA(host->io_base)); + } +} + +static int lpc32xx_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +{ + struct nand_chip *nand_chip = mtd->priv; + struct lpc32xx_nand_host *host = nand_chip->priv; + int i; + + for (i = 0; i < len; i++) + { + if (buf[i] != (uint8_t) __raw_readl(SLC_DATA(host->io_base))) + { + return -EFAULT; + } + } + + return 0; +} + +static void lpc32xx_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +{ + struct nand_chip *nand_chip = mtd->priv; + struct lpc32xx_nand_host *host = nand_chip->priv; + int i; + + for (i = 0; i < len; i++) + { + __raw_writel((u32) buf[i], SLC_DATA(host->io_base)); + } +} + +#ifdef CONFIG_MTD_PARTITIONS +const char *part_probes[] = { "cmdlinepart", NULL }; +#endif + +/* + * Probe for NAND controller + */ +static int __init lpc32xx_nand_probe(struct platform_device *pdev) +{ + struct lpc32xx_nand_host *host; + struct mtd_info *mtd; + struct nand_chip *nand_chip; + int res; + +#ifdef CONFIG_MTD_PARTITIONS + struct mtd_partition *partitions = NULL; + int num_partitions = 0; +#endif + + /* Allocate memory for the device structure (and zero it) */ + host = kzalloc(sizeof(struct lpc32xx_nand_host), GFP_KERNEL); + if (!host) { + printk(KERN_ERR "lpc32xx_nand: failed to allocate device structure.\n"); + return -ENOMEM; + } + + host->io_base = ioremap(pdev->resource[0].start, + pdev->resource[0].end - pdev->resource[0].start + 1); + if (host->io_base == NULL) { + printk(KERN_ERR "lpc32xx_nand: ioremap failed\n"); + res = -EIO; + goto err_exit1; + } + + mtd = &host->mtd; + nand_chip = &host->nand_chip; + host->ncfg = pdev->dev.platform_data; + + nand_chip->priv = host; /* link the private data structures */ + mtd->priv = nand_chip; + mtd->owner = THIS_MODULE; + + /* Get NAND clock */ + host->clk = clk_get(&pdev->dev, "nand_ck"); + if (IS_ERR(host->clk)) { + printk(KERN_ERR "lpc32xx_nand: Clock failure\n"); + res = -ENOENT; + goto err_exit2; + } + clk_enable(host->clk); + + /* Set address of NAND IO lines */ + nand_chip->IO_ADDR_R = SLC_DATA(host->io_base); + nand_chip->IO_ADDR_W = SLC_DATA(host->io_base); + nand_chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl; + nand_chip->dev_ready = lpc32xx_nand_device_ready; + nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */ + nand_chip->chip_delay = 20; /* 20us command delay time */ + nand_chip->read_byte = lpc32xx_read_byte; + nand_chip->read_buf = lpc32xx_read_buf; + nand_chip->verify_buf = lpc32xx_verify_buf; + nand_chip->write_buf = lpc32xx_write_buf; + + /* Init NAND controller */ + lpc32xx_nand_setup(host); + lpc32xx_wp_disable(host); + + platform_set_drvdata(pdev, host); + + /* Scan to find existance of the device */ + if (nand_scan(mtd, 1)) { + res = -ENXIO; + goto err_exit3; + } + +#ifdef CONFIG_MTD_PARTITIONS +#ifdef CONFIG_MTD_CMDLINE_PARTS + mtd->name = "lpc32xx_nand"; + num_partitions = parse_mtd_partitions(mtd, part_probes, + &partitions, 0); +#endif + if ((num_partitions <= 0) && (host->ncfg->partition_info)) + { + partitions = host->ncfg->partition_info(mtd->size, + &num_partitions); + } + + if ((!partitions) || (num_partitions == 0)) { + printk(KERN_ERR "lpc32xx_nand: No parititions defined, or unsupported device.\n"); + res = ENXIO; + nand_release(mtd); + goto err_exit3; + } + + res = add_mtd_partitions(mtd, partitions, num_partitions); +#else + res = add_mtd_device(mtd); +#endif + + if (!res) + { + return res; + } + + nand_release(mtd); +err_exit3: + clk_put(host->clk); + platform_set_drvdata(pdev, NULL); +err_exit2: + lpc32xx_wp_enable(host); + iounmap(host->io_base); +err_exit1: + kfree(host); + + return res; +} + +/* + * Remove NAND device. + */ +static int __devexit lpc32xx_nand_remove(struct platform_device *pdev) +{ + u32 tmp; + struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); + struct mtd_info *mtd = &host->mtd; + + nand_release(mtd); + + /* Force CE high */ + tmp = __raw_readl(SLC_CTRL(host->io_base)); + tmp &= ~SLCCFG_CE_LOW; + __raw_writel(tmp, SLC_CTRL(host->io_base)); + + lpc32xx_wp_enable(host); + clk_disable(host->clk); + clk_put(host->clk); + + iounmap(host->io_base); + kfree(host); + + return 0; +} + +#if defined(CONFIG_PM) +static int lpc32xx_nand_resume(struct platform_device *pdev) +{ + struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); + + /* Re-enable NAND clock */ + clk_enable(host->clk); + + /* Fresh init of NAND controller */ + lpc32xx_nand_setup(host); + + /* Disable write protect */ + lpc32xx_wp_disable(host); + + return 0; +} + +static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm) +{ + u32 tmp; + struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); + + /* Force CE high */ + tmp = __raw_readl(SLC_CTRL(host->io_base)); + tmp &= ~SLCCFG_CE_LOW; + __raw_writel(tmp, SLC_CTRL(host->io_base)); + + /* Enable write protect for safety */ + lpc32xx_wp_enable(host); + + /* Disable clock */ + clk_disable(host->clk); + + return 0; +} + +#else +#define lpc32xx_nand_resume NULL +#define lpc32xx_nand_suspend NULL +#endif + +static struct platform_driver lpc32xx_nand_driver = { + .probe = lpc32xx_nand_probe, + .remove = __devexit_p(lpc32xx_nand_remove), + .resume = lpc32xx_nand_resume, + .suspend = lpc32xx_nand_suspend, + .driver = { + .name = "lpc32xx-nand", + .owner = THIS_MODULE, + }, +}; + +static int __init lpc32xx_nand_init(void) +{ + return platform_driver_register(&lpc32xx_nand_driver); +} + +static void __exit lpc32xx_nand_exit(void) +{ + platform_driver_unregister(&lpc32xx_nand_driver); +} + + +module_init(lpc32xx_nand_init); +module_exit(lpc32xx_nand_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kevin Wells(kevin.wells@nxp.com)"); +MODULE_DESCRIPTION("NAND driver for the NXP LPC32XX SLC controller"); + diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/drivers/mtd/nand/Makefile linux-2.6.27.8/drivers/mtd/nand/Makefile --- linux-2.6.27.8-base/drivers/mtd/nand/Makefile 2009-01-08 11:43:30.000000000 -0800 +++ linux-2.6.27.8/drivers/mtd/nand/Makefile 2009-01-08 12:02:03.000000000 -0800 @@ -34,5 +34,6 @@ obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o +obj-$(CONFIG_MTD_NAND_SLC_LPC32XX) += lpc32xx_nand.o nand-objs := nand_base.o nand_bbt.o diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/drivers/net/Kconfig linux-2.6.27.8/drivers/net/Kconfig --- linux-2.6.27.8-base/drivers/net/Kconfig 2009-01-08 11:43:59.000000000 -0800 +++ linux-2.6.27.8/drivers/net/Kconfig 2009-01-08 12:02:03.000000000 -0800 @@ -1840,6 +1840,14 @@ Say Y here if you want to use the NE2000 compatible controller on the Renesas H8/300 processor. +config LPC32XX_MII + tristate "LPC32XX MII/RMII ethernet MAC" + depends on ARCH_LPC32XX + select PHYLIB + help + Say Y here if you want to use the LPC32XX MII/RMII + ethernet interface. + source "drivers/net/fs_enet/Kconfig" endif # NET_ETHERNET diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/drivers/net/lpc32xx_mii.c linux-2.6.27.8/drivers/net/lpc32xx_mii.c --- linux-2.6.27.8-base/drivers/net/lpc32xx_mii.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/drivers/net/lpc32xx_mii.c 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,1337 @@ +/* + * drivers/net/lpc32xx-mii.c + * (based on parts of the macb.c driver) + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 + */ + +//#define NET_DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define MODNAME "lpc32xx-net" +#define DRV_VERSION "$Revision: 1.00 $" +#define PHYDEF_ADDR 0x00 + +#define ENET_MAXF_SIZE 1536 +#define ENET_RX_DESC 128 /* Number of receive descriptors/buffers */ +#define ENET_TX_DESC 32 /* Number of transmit descriptors/buffers */ + +static int lpc32xx_net_hard_start_xmit(struct sk_buff *skb, + struct net_device *ndev); + +/* + * Transmit timeout, default 2.5 seconds. + */ +static int watchdog = 2500; +module_param(watchdog, int, 0400); +MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds"); + +/* + * Default local config if board config is not defined + */ +static struct lpc32xx_net_cfg __lpc32xx_local_net_config = +{ + .phy_irq = -1, + .phy_mask = 0xFFFFFFF0, +}; + +/* + * Device driver data structure + */ +struct netdata_local { + struct platform_device *pdev; + struct net_device *ndev; + spinlock_t lock; + void __iomem *net_base; + unsigned long net_region_start; + unsigned long net_region_size; + u32 msg_enable; + struct sk_buff *skb[ENET_TX_DESC]; + unsigned int last_tx_idx; + unsigned int num_used_tx_buffs; + struct mii_bus mii_bus; + struct phy_device *phy_dev; + struct clk *clk; + u32 dma_buff_base_p; + u32 dma_buff_base_v; + u32 dma_buff_size; + u32 tx_desc_v [ENET_TX_DESC]; + u32 tx_stat_v [ENET_TX_DESC]; + u32 tx_buff_v [ENET_TX_DESC]; + u32 rx_desc_v [ENET_RX_DESC]; + u32 rx_stat_v [ENET_RX_DESC]; + u32 rx_buff_v [ENET_RX_DESC]; + struct lpc32xx_net_cfg *ncfg; + int link; + int speed; + int duplex; +}; + +/* + * MAC support functions + */ +static void __lpc32xx_set_mac(struct netdata_local *pldat, u8 *mac) +{ + u32 tmp; + + /* Set station address */ + tmp = (u32) mac[0] | ((u32) mac[1] << 8); + __raw_writel(tmp, ENET_SA2(pldat->net_base)); + tmp = (u32) mac[2] | ((u32) mac[3] << 8); + __raw_writel(tmp, ENET_SA1(pldat->net_base)); + tmp = (u32) mac[4] | ((u32) mac[5] << 8); + __raw_writel(tmp, ENET_SA0(pldat->net_base)); + +#ifdef NET_DEBUG + printk("Ethernet MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); +#endif +} + +static void __lpc32xx_net_clock_enable(struct netdata_local *pldat, int enable) +{ + if (enable) + { + clk_enable(pldat->clk); + } + else + { + clk_disable(pldat->clk); + } +} + +static void __lpc32xx_params_setup(struct netdata_local *pldat) +{ + u32 tmp; + + if (pldat->duplex == DUPLEX_FULL) + { + tmp = __raw_readl(ENET_MAC2(pldat->net_base)); + tmp |= MAC2_FULL_DUPLEX; + __raw_writel(tmp, ENET_MAC2(pldat->net_base)); + tmp = __raw_readl(ENET_COMMAND(pldat->net_base)); + tmp |= COMMAND_FULLDUPLEX; + __raw_writel(tmp, ENET_COMMAND(pldat->net_base)); + __raw_writel(IPGT_LOAD(0x15), ENET_IPGT(pldat->net_base)); + } + else + { + tmp = __raw_readl(ENET_MAC2(pldat->net_base)); + tmp &= ~MAC2_FULL_DUPLEX; + __raw_writel(tmp, ENET_MAC2(pldat->net_base)); + tmp = __raw_readl(ENET_COMMAND(pldat->net_base)); + tmp &= ~COMMAND_FULLDUPLEX; + __raw_writel(tmp, ENET_COMMAND(pldat->net_base)); + __raw_writel(IPGT_LOAD(0x12), ENET_IPGT(pldat->net_base)); + } + + if (pldat->speed == SPEED_100) + { + __raw_writel(SUPP_SPEED, ENET_SUPP(pldat->net_base)); + } + else + { + __raw_writel(0, ENET_SUPP(pldat->net_base)); + } +} + +static void __lpc32xx_eth_reset(struct netdata_local *pldat) +{ + /* Reset all MAC logic */ + __raw_writel((MAC1_RESET_TX | MAC1_RESET_MCS_TX | MAC1_RESET_RX | + MAC1_RESET_MCS_RX | MAC1_SIMULATION_RESET | MAC1_SOFT_RESET), + ENET_MAC1(pldat->net_base)); + __raw_writel((COMMAND_REG_RESET | COMMAND_TXRESET | COMMAND_RXRESET), + ENET_COMMAND(pldat->net_base)); + msleep(10); +} + +static int __lpc32xx_mii_mngt_reset(struct netdata_local *pldat) +{ + /* Reset MII management hardware */ + __raw_writel(MCFG_RESET_MII_MGMT, ENET_MCFG(pldat->net_base)); + msleep(1); + + /* Setup MII clock to slowest rate with a /28 divider */ + __raw_writel(MCFG_CLOCK_SELECT(MCFG_CLOCK_HOST_DIV_28), + ENET_MCFG(pldat->net_base)); + + return 0; +} + +static u32 __ptr_align(u32 pbuff) +{ + pbuff &= 0xFFFFFFF0; + pbuff += 0x10; + + return pbuff; +} + +static inline u32 __va_to_pa(u32 addr, struct netdata_local *pldat) +{ + u32 phaddr; + + phaddr = addr - pldat->dma_buff_base_v; + phaddr += pldat->dma_buff_base_p; + + return phaddr; +} + +/* Setup TX/RX descriptors */ +static void __lpc32xx_txrx_desc_setup(struct netdata_local *pldat) +{ + u32 tbuff, *ptxstat; + int i; + struct txrx_desc_t *ptxrxdesc; + struct rx_status_t *prxstat; + + tbuff = __ptr_align(pldat->dma_buff_base_v); + + /* Setup TX descriptors, status, and buffers */ + for (i = 0; i < ENET_TX_DESC; i++) + { + pldat->tx_desc_v [i] = tbuff; + tbuff += sizeof(struct txrx_desc_t); + } + for (i = 0; i < ENET_TX_DESC; i++) + { + pldat->tx_stat_v [i] = tbuff; + tbuff += sizeof(u32); + } + tbuff = __ptr_align(tbuff); + for (i = 0; i < ENET_TX_DESC; i++) + { + pldat->tx_buff_v [i] = tbuff; + tbuff += ENET_MAXF_SIZE; + } + + /* Setup RX descriptors, status, and buffers */ + for (i = 0; i < ENET_RX_DESC; i++) + { + pldat->rx_desc_v [i] = tbuff; + tbuff += sizeof(struct txrx_desc_t); + } + tbuff = __ptr_align(tbuff); + for (i = 0; i < ENET_RX_DESC; i++) + { + pldat->rx_stat_v [i] = tbuff; + tbuff += sizeof(struct rx_status_t); + } + tbuff = __ptr_align(tbuff); + for (i = 0; i < ENET_RX_DESC; i++) + { + pldat->rx_buff_v [i] = tbuff; + tbuff += ENET_MAXF_SIZE; + } + + /* Map the TX descriptors to the TX buffers in hardware */ + for (i = 0; i < ENET_TX_DESC; i++) + { + ptxstat = (u32 *) pldat->tx_stat_v [i]; + ptxrxdesc = (struct txrx_desc_t *) pldat->tx_desc_v [i]; + + ptxrxdesc->packet = __va_to_pa(pldat->tx_buff_v [i], pldat); + ptxrxdesc->control = 0; + *ptxstat = 0; + } + + /* Map the RX descriptors to the RX buffers in hardware */ + for (i = 0; i < ENET_RX_DESC; i++) + { + prxstat = (struct rx_status_t *) pldat->rx_stat_v [i]; + ptxrxdesc = (struct txrx_desc_t *) pldat->rx_desc_v [i]; + + ptxrxdesc->packet = __va_to_pa(pldat->rx_buff_v [i], pldat); + ptxrxdesc->control = 0x80000000 | (ENET_MAXF_SIZE - 1); + prxstat->statusinfo = 0; + prxstat->statushashcrc = 0; + } + + /* Setup base addresses in hardware to point to buffers and descriptors */ + __raw_writel((ENET_TX_DESC - 1), ENET_TXDESCRIPTORNUMBER(pldat->net_base)); + __raw_writel(__va_to_pa(pldat->tx_desc_v [0], pldat), ENET_TXDESCRIPTOR(pldat->net_base)); + __raw_writel(__va_to_pa(pldat->tx_stat_v [0], pldat), ENET_TXSTATUS(pldat->net_base)); + __raw_writel((ENET_RX_DESC - 1), ENET_RXDESCRIPTORNUMBER(pldat->net_base)); + __raw_writel(__va_to_pa(pldat->rx_desc_v [0], pldat), ENET_RXDESCRIPTOR(pldat->net_base)); + __raw_writel(__va_to_pa(pldat->rx_stat_v [0], pldat), ENET_RXSTATUS(pldat->net_base)); +} + +static void __lpc32xx_eth_init(struct netdata_local *pldat) +{ + u32 tmp; + + /* Disable controller and reset */ + tmp = __raw_readl(ENET_COMMAND(pldat->net_base)); + tmp &= ~COMMAND_RXENABLE | COMMAND_TXENABLE; + __raw_writel(tmp, ENET_COMMAND(pldat->net_base)); + tmp = __raw_readl(ENET_MAC1(pldat->net_base)); + tmp &= ~MAC1_RECV_ENABLE; + __raw_writel(tmp, ENET_MAC1(pldat->net_base)); + + /* Initial MAC setup */ + __raw_writel(MAC1_PASS_ALL_RX_FRAMES, ENET_MAC1(pldat->net_base)); + __raw_writel((MAC2_PAD_CRC_ENABLE | MAC2_CRC_ENABLE), + ENET_MAC2(pldat->net_base)); + __raw_writel(ENET_MAXF_SIZE, ENET_MAXF(pldat->net_base)); + + /* Collision window, gap */ + __raw_writel((CLRT_LOAD_RETRY_MAX(0xF) | + CLRT_LOAD_COLLISION_WINDOW(0x37)), ENET_CLRT(pldat->net_base)); + __raw_writel(IPGR_LOAD_PART2(0x12), ENET_IPGR(pldat->net_base)); + +#if defined (MAC_LPC32XX_MII_SUPPORT) + __raw_writel(COMMAND_PASSRUNTFRAME, ENET_COMMAND(pldat->net_base)); +#else + __raw_writel((COMMAND_PASSRUNTFRAME | COMMAND_RMII), + ENET_COMMAND(pldat->net_base)); + __raw_writel(SUPP_RESET_RMII, ENET_SUPP(pldat->net_base)); + msleep(10); +#endif + + __lpc32xx_params_setup(pldat); + + /* Setup TX and RX descriptors */ + __lpc32xx_txrx_desc_setup(pldat); + + /* Setup packet filtering */ + __raw_writel((RXFLTRW_ACCEPTUBROADCAST | RXFLTRW_ACCEPTPERFECT), + ENET_RXFILTER_CTRL(pldat->net_base)); + + /* Clear and enable interrupts */ + __raw_writel(0xFFFF, ENET_INTCLEAR(pldat->net_base)); + __raw_writel((MACINT_RXDONEINTEN | MACINT_TXDONEINTEN), + ENET_INTENABLE(pldat->net_base)); + + /* Get the next TX buffer output index */ + pldat->num_used_tx_buffs = 0; + pldat->last_tx_idx = + __raw_readl(ENET_TXCONSUMEINDEX(pldat->net_base)); + + /* Enable controller */ + tmp = __raw_readl(ENET_COMMAND(pldat->net_base)); + tmp |= COMMAND_RXENABLE | COMMAND_TXENABLE; + __raw_writel(tmp, ENET_COMMAND(pldat->net_base)); + tmp = __raw_readl(ENET_MAC1(pldat->net_base)); + tmp |= MAC1_RECV_ENABLE; + __raw_writel(tmp, ENET_MAC1(pldat->net_base)); +} + +static void __lpc32xx_net_shutdown(struct netdata_local *pldat) +{ + /* Reset ethernet and power down PHY */ + __lpc32xx_eth_reset(pldat); + __raw_writel(0, ENET_MAC1(pldat->net_base)); + __raw_writel(0, ENET_MAC2(pldat->net_base)); +} + +/* + * MAC<--->PHY support functions + */ +static int lpc32xx_mdio_read(struct mii_bus *bus, int phy_id, int phyreg) +{ + struct netdata_local *pldat = bus->priv; + int lps; + u32 tmp; + + __raw_writel(((phy_id << 8) | phyreg), ENET_MADR(pldat->net_base)); + __raw_writel(MCMD_READ, ENET_MCMD(pldat->net_base)); + + /* Wait for unbusy status */ + lps = 50; + tmp = __raw_readl(ENET_MIND(pldat->net_base)); + while ((lps > 0) && (tmp & (MIND_BUSY | MIND_MII_LINK_FAIL))) + { + msleep(1); + tmp = __raw_readl(ENET_MIND(pldat->net_base)); + lps--; + } + lps = (int) __raw_readl(ENET_MRDD(pldat->net_base)); + __raw_writel(0, ENET_MCMD(pldat->net_base)); + + return lps; +} + +static int lpc32xx_mdio_write(struct mii_bus *bus, int phy_id, int phyreg, + u16 phydata) +{ + struct netdata_local *pldat = bus->priv; + int lps; + u32 tmp; + + __raw_writel(((phy_id << 8) | phyreg), ENET_MADR(pldat->net_base)); + __raw_writel(phydata, ENET_MWTD(pldat->net_base)); + + /* Wait for completion */ + lps = 50; + tmp = __raw_readl(ENET_MIND(pldat->net_base)); + while ((lps > 0) && (tmp & MIND_BUSY)) + { + msleep(1); + tmp = __raw_readl(ENET_MIND(pldat->net_base)); + lps--; + } + + return 0; +} + +static int lpc32xx_mdio_reset(struct mii_bus *bus) +{ + struct netdata_local *pldat = bus->priv; + + return __lpc32xx_mii_mngt_reset(pldat); +} + +static void lpc32xx_handle_link_change(struct net_device *ndev) +{ + struct netdata_local *pldat = netdev_priv(ndev); + struct phy_device *phydev = pldat->phy_dev; + unsigned long flags; + + int status_change = 0; + + spin_lock_irqsave(&pldat->lock, flags); + + if (phydev->link) + { + if ((pldat->speed != phydev->speed) || + (pldat->duplex != phydev->duplex)) + { + pldat->speed = phydev->speed; + pldat->duplex = phydev->duplex; + status_change = 1; + } + } + + if (phydev->link != pldat->link) + { + if (!phydev->link) + { + pldat->speed = 0; + pldat->duplex = -1; + } + pldat->link = phydev->link; + + status_change = 1; + } + + spin_unlock_irqrestore(&pldat->lock, flags); + + if (status_change) + { + /* Update hardware interface to PHY from PHY status */ + __lpc32xx_params_setup(pldat); + } +} + +static int lpc32xx_mii_probe(struct net_device *ndev) +{ + struct netdata_local *pldat = netdev_priv(ndev); + struct phy_device *phydev = NULL; + int phy_addr; + + /* find the first phy */ + for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) + { + if (pldat->mii_bus.phy_map[phy_addr]) + { + phydev = pldat->mii_bus.phy_map[phy_addr]; + break; + } + } + + if (!phydev) + { + printk (KERN_ERR "%s: no PHY found\n", ndev->name); + return -1; + } + + /* Attach to the PHY */ +#if defined (MAC_LPC32XX_MII_SUPPORT) + phydev = phy_connect(ndev, phydev->dev.bus_id, + &lpc32xx_handle_link_change, 0, PHY_INTERFACE_MODE_MII); +#else + phydev = phy_connect(ndev, phydev->dev.bus_id, + &lpc32xx_handle_link_change, 0, PHY_INTERFACE_MODE_RMII); +#endif + + if (IS_ERR(phydev)) + { + printk(KERN_ERR "%s: Could not attach to PHY\n", ndev->name); + return PTR_ERR(phydev); + } + + /* mask with MAC supported features */ + phydev->supported &= PHY_BASIC_FEATURES; + + phydev->advertising = phydev->supported; + + pldat->link = 0; + pldat->speed = 0; + pldat->duplex = -1; + pldat->phy_dev = phydev; + + return 0; +} + +static int lpc32xx_mii_init(struct netdata_local *pldat) +{ + int err = -ENXIO, i; + + /* Setup MII mode */ +#if defined (MAC_LPC32XX_MII_SUPPORT) + __raw_writel(COMMAND_PASSRUNTFRAME, ENET_COMMAND(pldat->net_base)); +#else + __raw_writel((COMMAND_PASSRUNTFRAME | COMMAND_RMII), + ENET_COMMAND(pldat->net_base)); + __raw_writel(SUPP_RESET_RMII, ENET_SUPP(pldat->net_base)); + msleep(10); +#endif + + pldat->mii_bus.name = "LPC32XX_mii_bus"; + pldat->mii_bus.read = &lpc32xx_mdio_read; + pldat->mii_bus.write = &lpc32xx_mdio_write; + pldat->mii_bus.reset = &lpc32xx_mdio_reset; + snprintf(pldat->mii_bus.id, MII_BUS_ID_SIZE, "%x", pldat->pdev->id); + pldat->mii_bus.priv = pldat; + pldat->mii_bus.dev = &pldat->ndev->dev; + pldat->mii_bus.phy_mask = 0xFFFFFFF0; + + if (pldat->ncfg) + { + pldat->mii_bus.phy_mask = pldat->ncfg->phy_mask; + } + + pldat->mii_bus.irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); + if (!pldat->mii_bus.irq) { + err = -ENOMEM; + goto err_out; + } + + for (i = 0; i < PHY_MAX_ADDR; i++) + { + pldat->mii_bus.irq[i] = PHY_POLL; + } + + platform_set_drvdata(pldat->ndev, &pldat->mii_bus); + + if (mdiobus_register(&pldat->mii_bus)) + { + goto err_out_free_mdio_irq; + } + + if (lpc32xx_mii_probe(pldat->ndev) != 0) + { + goto err_out_unregister_bus; + } + + return 0; + +err_out_unregister_bus: + mdiobus_unregister(&pldat->mii_bus); +err_out_free_mdio_irq: + kfree(pldat->mii_bus.irq); +err_out: + return err; +} + +static void __lpc32xx_handle_xmit(struct net_device *ndev) +{ + struct netdata_local *pldat = netdev_priv(ndev); + struct sk_buff *skb; + unsigned int txcidx, *ptxstat, txstat; + + txcidx = __raw_readl(ENET_TXCONSUMEINDEX(pldat->net_base)); + while (pldat->last_tx_idx != txcidx) + { + skb = (struct sk_buff *) pldat->skb[pldat->last_tx_idx]; + + /* A buffer is available, get buffer status */ + ptxstat = (unsigned int *) pldat->tx_stat_v[pldat->last_tx_idx]; + txstat = *ptxstat; + + /* Next buffer and decrement used buffer counter */ + pldat->num_used_tx_buffs--; + pldat->last_tx_idx++; + if (pldat->last_tx_idx >= ENET_TX_DESC) + { + pldat->last_tx_idx = 0; + } + + /* Update collision counter */ + ndev->stats.collisions += ((txstat >> 21) & 0xF); + + /* Any errors occurred? */ + if (txstat & 0x80000000) + { + if (txstat & 0x20000000) + { + /* FIFO underrun */ + ndev->stats.tx_fifo_errors++; + ndev->stats.tx_errors++; + } + if (txstat & 0x10000000) + { + /* Late collision */ + ndev->stats.tx_aborted_errors++; + ndev->stats.tx_errors++; + } + if (txstat & 0x08000000) + { + /* Excessive collision */ + ndev->stats.tx_aborted_errors++; + ndev->stats.tx_errors++; + } + if (txstat & 0x04000000) + { + /* Defer limit */ + ndev->stats.tx_aborted_errors++; + ndev->stats.tx_errors++; + } + + /* Buffer transmit failed, requeue it */ + lpc32xx_net_hard_start_xmit(skb, ndev); + } + else + { + /* Update stats */ + ndev->stats.tx_packets++; + ndev->stats.tx_bytes += skb->len; + + /* Free buffer */ + dev_kfree_skb_irq(skb); + } + + txcidx = __raw_readl(ENET_TXCONSUMEINDEX(pldat->net_base)); + } + + if (netif_queue_stopped(ndev)) + { + netif_wake_queue(ndev); + } +} + +static void __lpc32xx_handle_recv(struct net_device *ndev) +{ + struct netdata_local *pldat = netdev_priv(ndev); + struct sk_buff *skb; + int rxconsidx, len, ethst; + struct rx_status_t *prxstat; + u8 *prdbuf; + + /* Get the current RX buffer indexes */ + rxconsidx = (int) __raw_readl(ENET_RXCONSUMEINDEX(pldat->net_base)); + while (rxconsidx != (int) __raw_readl(ENET_RXPRODUCEINDEX(pldat->net_base))) + { + /* Get pointer to receive status */ + prxstat = (struct rx_status_t *) pldat->rx_stat_v [rxconsidx]; + len = (prxstat->statusinfo & 0x7FF) + 1; + + /* Status error? */ + ethst = prxstat->statusinfo; + if ((ethst & 0xBF800000) == 0x84000000) + { + /* Range error, can be ignored */ + ethst &= ~0x80000000; + } + + if (ethst & 0x80000000) + { + /* Check statuses */ + if (prxstat->statusinfo & (1 << 28)) + { + /* Overrun error */ + ndev->stats.rx_fifo_errors++; + } + else if (prxstat->statusinfo & (1 << 23)) + { + /* CRC error */ + ndev->stats.rx_crc_errors++; + } + else if (prxstat->statusinfo & (1 << 25)) + { + /* Length error */ + ndev->stats.rx_length_errors++; + } + else if (prxstat->statusinfo & 0x80000000) + { + /* Other error */ + ndev->stats.rx_length_errors++; + } + ndev->stats.rx_errors++; + } + else + { + /* Packet is good */ + skb = dev_alloc_skb(len + 8); + if (!skb) + { + ndev->stats.rx_dropped++; + } + else + { + skb_reserve(skb, 8); + prdbuf = skb_put(skb, (len - 0)); + + /* Copy packer from buffer */ + memcpy(prdbuf, (void *) pldat->rx_buff_v [rxconsidx], len); + + /* Pass to upper layer */ + skb->protocol = eth_type_trans(skb, ndev); + netif_rx(skb); + ndev->last_rx = jiffies; + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += len; + } + } + + /* Increment consume index */ + rxconsidx = rxconsidx + 1; + if (rxconsidx >= ENET_RX_DESC) + { + rxconsidx = 0; + } + __raw_writel((u32) rxconsidx, ENET_RXCONSUMEINDEX(pldat->net_base)); + } +} + +static irqreturn_t __lpc32xx_eth_interrupt(int irq, void *dev_id) +{ + struct net_device *ndev = dev_id; + struct netdata_local *pldat = netdev_priv(ndev); + u32 tmp; + + spin_lock(&pldat->lock); + + /* Get the interrupt status */ + tmp = __raw_readl(ENET_INTSTATUS(pldat->net_base)); + + while (tmp) + { + /* Clear interrupts */ + __raw_writel(tmp, ENET_INTCLEAR(pldat->net_base)); + + /* Transmit complete? */ + if (tmp & (MACINT_TXUNDERRUNINTEN | MACINT_TXERRORINTEN | + MACINT_TXFINISHEDINTEN | MACINT_TXDONEINTEN)) + { + __lpc32xx_handle_xmit(ndev); + } + + /* Receive buffer available */ + if (tmp & (MACINT_RXOVERRUNINTEN | MACINT_RXERRORONINT | + MACINT_RXFINISHEDINTEN | MACINT_RXDONEINTEN)) + { + __lpc32xx_handle_recv(ndev); + } + + /* Recheck the interrupt status */ + tmp = __raw_readl(ENET_INTSTATUS(pldat->net_base)); + } + + spin_unlock(&pldat->lock); + + return IRQ_HANDLED; +} + +static int lpc32xx_net_close(struct net_device *ndev) +{ + unsigned long flags; + struct netdata_local *pldat = netdev_priv(ndev); + + if (netif_msg_ifdown(pldat)) + { + dev_dbg(&pldat->pdev->dev, "shutting down %s\n", ndev->name); + } + + netif_stop_queue(ndev); + + if (pldat->phy_dev) + { + phy_stop(pldat->phy_dev); + } + + spin_lock_irqsave(&pldat->lock, flags); + __lpc32xx_eth_reset(pldat); + netif_carrier_off(ndev); + __raw_writel(0, ENET_MAC1(pldat->net_base)); + __raw_writel(0, ENET_MAC2(pldat->net_base)); + spin_unlock_irqrestore(&pldat->lock, flags); + + __lpc32xx_net_clock_enable(pldat, 0); + + return 0; +} + +static int lpc32xx_net_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct netdata_local *pldat = netdev_priv(ndev); + unsigned int len, txidx; + u32 *ptxstat; + struct txrx_desc_t *ptxrxdesc; + + len = skb->len; + + spin_lock_irq(&pldat->lock); + + if (pldat->num_used_tx_buffs >= (ENET_TX_DESC - 1)) + { + /* This function should never be called when there are no + buffers, log the error */ + netif_stop_queue(ndev); + spin_unlock_irq(&pldat->lock); + dev_err(&pldat->pdev->dev, + "BUG! TX request when no free TX buffers!\n"); + return 1; + } + + /* Get the next TX descriptor index */ + txidx = __raw_readl(ENET_TXPRODUCEINDEX(pldat->net_base)); + + /* Setup control for the transfer */ + ptxstat = (u32 *) pldat->tx_stat_v [txidx]; + *ptxstat = 0; + ptxrxdesc = (struct txrx_desc_t *) pldat->tx_desc_v [txidx]; + ptxrxdesc->control = (len - 1) | 0xC0000000; + + /* Copy data to the DMA buffer */ + memcpy((void *) pldat->tx_buff_v [txidx], skb->data, len); + + /* Save the buffer and increment the buffer counter */ + pldat->skb[txidx] = skb; + pldat->num_used_tx_buffs++; + + /* Start transmit */ + txidx++; + if (txidx >= ENET_TX_DESC) + { + txidx = 0; + } + __raw_writel((u32) txidx, ENET_TXPRODUCEINDEX(pldat->net_base)); + + /* Stop queue if no more TX buffers */ + if (pldat->num_used_tx_buffs >= (ENET_TX_DESC - 1)) + { + netif_stop_queue(ndev); + } + + spin_unlock_irq(&pldat->lock); + ndev->trans_start = jiffies; + + return 0; +} + +static void lpc32xx_net_timeout(struct net_device *ndev) +{ + struct netdata_local *pldat = netdev_priv(ndev); + + /* This should never happen and indicates a problem */ + dev_err(&pldat->pdev->dev, "BUG! TX timeout occurred!\n"); +} + +static void lpc32xx_net_set_multicast_list(struct net_device *ndev) +{ + struct netdata_local *pldat = netdev_priv(ndev); + struct dev_mc_list *mcptr = ndev->mc_list; + int i, mc_cnt = ndev->mc_count; + u32 tmp32, hash_val, hashlo, hashhi; + unsigned long flags; + + spin_lock_irqsave(&pldat->lock, flags); + + /* Set station address */ + __lpc32xx_set_mac(pldat, ndev->dev_addr); + + tmp32 = RXFLTRW_ACCEPTUBROADCAST | RXFLTRW_ACCEPTPERFECT; + + if (ndev->flags & IFF_PROMISC) + { + tmp32 |= RXFLTRW_ACCEPTUNICAST | RXFLTRW_ACCEPTUNICASTHASH | + RXFLTRW_ACCEPTUMULTICASTHASH; + } + if (ndev->flags & IFF_ALLMULTI) + { + tmp32 |= RXFLTRW_ACCEPTUMULTICAST; + } + __raw_writel(tmp32, ENET_RXFILTER_CTRL(pldat->net_base)); + + + /* Set initial hash table */ + hashlo = 0x0; + hashhi = 0x80000000; + + /* 64 bits : multicast address in hash table */ + for (i = 0; i < mc_cnt; i++, mcptr = mcptr->next) + { + hash_val = ether_crc_le(6, mcptr->dmi_addr) & 0x3f; + + if (hash_val >= 32) + { + hashhi |= 1 << (32 - hash_val); + } + else + { + hashlo |= 1 << hash_val; + } + } + + __raw_writel(hashlo, ENET_HASHFILTERL(pldat->net_base)); + __raw_writel(hashhi, ENET_HASHFILTERH(pldat->net_base)); + + spin_unlock_irqrestore(&pldat->lock, flags); +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void lpc32xx_net_poll_controller(struct net_device *ndev) +{ + disable_irq(ndev->irq); + __lpc32xx_eth_interrupt(dev->irq, ndev); + enable_irq(ndev->irq); +} +#endif + +static int lpc32xx_net_ioctl(struct net_device *ndev, struct ifreq *req, int cmd) +{ + struct netdata_local *pldat = netdev_priv(ndev); + struct phy_device *phydev = pldat->phy_dev; + + if (!netif_running(ndev)) + { + return -EINVAL; + } + + if (!phydev) + { + return -ENODEV; + } + + return phy_mii_ioctl(phydev, if_mii(req), cmd); +} + +static int lpc32xx_net_open(struct net_device *ndev) +{ + struct netdata_local *pldat = netdev_priv(ndev); + + /* if the phy is not yet registered, retry later*/ + if (!pldat->phy_dev) + { + return -EAGAIN; + } + + if (netif_msg_ifup(pldat)) + { + dev_dbg(&pldat->pdev->dev, "enabling %s\n", ndev->name); + } + + if (!is_valid_ether_addr(ndev->dev_addr)) + { + return -EADDRNOTAVAIL; + } + + __lpc32xx_net_clock_enable(pldat, 1); + + /* Reset and initialize */ + __lpc32xx_eth_reset(pldat); + __lpc32xx_eth_init(pldat); + + /* schedule a link state check */ + phy_start(pldat->phy_dev); + netif_start_queue(ndev); + + return 0; +} + +/* + * Ethtool ops + */ +static void lpc32xx_net_ethtool_getdrvinfo(struct net_device *ndev, + struct ethtool_drvinfo *info) +{ + struct netdata_local *pldat = netdev_priv(ndev); + + strcpy(info->driver, MODNAME); + strcpy(info->version, DRV_VERSION); + strcpy(info->bus_info, pldat->pdev->dev.bus_id); +} + +static u32 lpc32xx_net_ethtool_getmsglevel(struct net_device *ndev) +{ + struct netdata_local *pldat = netdev_priv(ndev); + + return pldat->msg_enable; +} + +static void lpc32xx_net_ethtool_setmsglevel(struct net_device *ndev, u32 level) +{ + struct netdata_local *pldat = netdev_priv(ndev); + + pldat->msg_enable = level; +} + +static int lpc32xx_net_ethtool_getsettings(struct net_device *ndev, + struct ethtool_cmd *cmd) +{ + struct netdata_local *pldat = netdev_priv(ndev); + struct phy_device *phydev = pldat->phy_dev; + + if (!phydev) + { + return -ENODEV; + } + + return phy_ethtool_gset(phydev, cmd); +} + +static int lpc32xx_net_ethtool_setsettings(struct net_device *ndev, + struct ethtool_cmd *cmd) +{ + struct netdata_local *pldat = netdev_priv(ndev); + struct phy_device *phydev = pldat->phy_dev; + + if (!phydev) + { + return -ENODEV; + } + + return phy_ethtool_sset(phydev, cmd); +} + +static const struct ethtool_ops lpc32xx_net_ethtool_ops = { + .get_drvinfo = lpc32xx_net_ethtool_getdrvinfo, + .get_settings = lpc32xx_net_ethtool_getsettings, + .set_settings = lpc32xx_net_ethtool_setsettings, + .get_msglevel = lpc32xx_net_ethtool_getmsglevel, + .set_msglevel = lpc32xx_net_ethtool_setmsglevel, + .get_link = ethtool_op_get_link, +}; + +static int lpc32xx_net_drv_probe(struct platform_device *pdev) +{ + struct resource *res; + struct net_device *ndev; + struct netdata_local *pldat; + struct phy_device *phydev; + dma_addr_t dma_handle; + int irq, ret; + + /* Get platform resources */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + irq = platform_get_irq(pdev, 0); + if ((!res) || (irq < 0) || (irq >= NR_IRQS)) + { + dev_err(&pdev->dev, "error getting resources.\n"); + ret = -ENXIO; + goto err_exit; + } + + /* Allocate net driver data structure */ + ndev = alloc_etherdev(sizeof(struct netdata_local)); + if (!ndev) { + dev_err(&pdev->dev, "could not allocate device.\n"); + ret = -ENOMEM; + goto err_exit; + } + + SET_NETDEV_DEV(ndev, &pdev->dev); + + pldat = netdev_priv(ndev); + pldat->pdev = pdev; + pldat->ndev = ndev; + + spin_lock_init(&pldat->lock); + + /* Save resources */ + pldat->net_region_start = res->start; + pldat->net_region_size = res->end - res->start + 1; + ndev->irq = irq; + + /* Get clock for the device */ + pldat->clk = clk_get(&ndev->dev, "net_ck"); + if (IS_ERR(pldat->clk)) { + ret = PTR_ERR(pldat->clk); + goto err_out_free_dev; + } + + /* Enable network clock */ + __lpc32xx_net_clock_enable(pldat, 1); + + /* Map IO space */ + pldat->net_base = ioremap(pldat->net_region_start, pldat->net_region_size); + if (!pldat->net_base) + { + dev_err(&pdev->dev, "failed to map registers, aborting.\n"); + ret = -ENOMEM; + goto err_out_disable_clocks; + } + ret = request_irq(ndev->irq, __lpc32xx_eth_interrupt, 0, + ndev->name, ndev); + if (ret) { + printk(KERN_ERR + "%s: Unable to request IRQ %d (error %d)\n", + ndev->name, ndev->irq, ret); + goto err_out_iounmap; + } + + /* Fill in the fields of the device structure with ethernet values. */ + ether_setup(ndev); + + /* Setup driver functions */ + ndev->open = lpc32xx_net_open; + ndev->stop = lpc32xx_net_close; + ndev->hard_start_xmit = lpc32xx_net_hard_start_xmit; + ndev->tx_timeout = lpc32xx_net_timeout; + ndev->watchdog_timeo = msecs_to_jiffies(watchdog); + ndev->set_multicast_list = lpc32xx_net_set_multicast_list; + ndev->ethtool_ops = &lpc32xx_net_ethtool_ops; + ndev->do_ioctl = &lpc32xx_net_ioctl; +#ifdef CONFIG_NET_POLL_CONTROLLER + ndev->poll_controller = lpc32xx_net_poll_controller; +#endif + ndev->base_addr = pldat->net_region_start; + + /* Save board specific configuration */ + pldat->ncfg = (struct lpc32xx_net_cfg *) pdev->dev.platform_data; + if (pldat->ncfg == NULL) + { + printk(KERN_INFO "%s : WARNING: No board MAC address provided\n", + ndev->name); + pldat->ncfg = &__lpc32xx_local_net_config; + } + + /* Get size of DMA buffers/descriptors region */ + pldat->dma_buff_size = (ENET_TX_DESC + ENET_RX_DESC) * (ENET_MAXF_SIZE + + sizeof(struct txrx_desc_t) + sizeof(struct rx_status_t)); + pldat->dma_buff_size += 4096; /* Allows room for alignment */ + + /* Align on the next highest page entry size */ + pldat->dma_buff_size &= 0Xfffff000; + pldat->dma_buff_size += 0X00001000; + + /* Allocate a chunk of memory for the DMA ethernet buffers and descriptors */ + pldat->dma_buff_base_v = (u32) dma_alloc_coherent(&pldat->pdev->dev, pldat->dma_buff_size, + &dma_handle, GFP_KERNEL); + if (pldat->dma_buff_base_v == (u32) NULL) + { + dev_err(&pdev->dev, "error getting DMA region.\n"); + ret = -ENOMEM; + goto err_out_free_irq; + } + pldat->dma_buff_base_p = (u32) dma_handle; + +#ifdef NET_DEBUG + printk(KERN_INFO "Ethernet net MAC resources\n"); + printk(KERN_INFO "IO address start :0x%08x\n", (u32) pldat->net_region_start); + printk(KERN_INFO "IO address size :%d\n", (u32) pldat->net_region_size); + printk(KERN_INFO "IO address (mapped) :0x%08x\n", (u32) pldat->net_base); + printk(KERN_INFO "IRQ number :%d\n", ndev->irq); + printk(KERN_INFO "DMA buffer size :%d\n", pldat->dma_buff_size); + printk(KERN_INFO "DMA buffer P address :0x%08x\n", pldat->dma_buff_base_p); + printk(KERN_INFO "DMA buffer V address :0x%08x\n", pldat->dma_buff_base_v); +#endif + + /* Get the board MAC address */ + if (pldat->ncfg->get_mac_addr != NULL) + { + ret = pldat->ncfg->get_mac_addr(ndev->dev_addr); + if (ret) + { + /* Mac address load error */ + goto err_out_dma_unmap; + } + } + + if (!is_valid_ether_addr(ndev->dev_addr)) + { + printk(KERN_INFO "%s: Invalid ethernet MAC address. Please " + "set using ifconfig\n", ndev->name); + } + + /* Reset the ethernet controller */ + __lpc32xx_eth_reset(pldat); + + /* then shut everything down to save power */ + __lpc32xx_net_shutdown(pldat); + + /* Set default parameters */ + pldat->msg_enable = NETIF_MSG_LINK; + + /* Force an MII interface reset and clock setup */ + __lpc32xx_mii_mngt_reset(pldat); + + /* Force default PHY interface setup in chip, this will probably be + changed by the PHY driver */ + pldat->link = 0; + pldat->speed = 100; + pldat->duplex = DUPLEX_FULL; + __lpc32xx_params_setup(pldat); + + ret = register_netdev(ndev); + if (ret) { + dev_err(&pdev->dev, "Cannot register net device, aborting.\n"); + goto err_out_dma_unmap; + } + platform_set_drvdata(pdev, ndev); + + if (lpc32xx_mii_init(pldat) != 0) { + goto err_out_unregister_netdev; + } + + printk(KERN_INFO "%s: LPC32XX mac at 0x%08lx irq %d\n", + ndev->name, ndev->base_addr, ndev->irq); + + phydev = pldat->phy_dev; + printk(KERN_INFO "%s: attached PHY driver [%s] " + "(mii_bus:phy_addr=%s, irq=%d)\n", + ndev->name, phydev->drv->name, phydev->dev.bus_id, phydev->irq); + + return 0; + +err_out_unregister_netdev: + platform_set_drvdata(pdev, NULL); + unregister_netdev(ndev); +err_out_dma_unmap: + dma_free_coherent(&pldat->pdev->dev, pldat->dma_buff_size, + (void *) pldat->dma_buff_base_v, (dma_addr_t) pldat->dma_buff_base_p); +err_out_free_irq: + free_irq(ndev->irq, ndev); +err_out_iounmap: + iounmap(pldat->net_base); +err_out_disable_clocks: + clk_disable(pldat->clk); + clk_put(pldat->clk); +err_out_free_dev: + free_netdev(ndev); +err_exit: + printk("%s: not found (%d).\n", MODNAME, ret); + return ret; +} + +static int lpc32xx_net_drv_remove(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct netdata_local *pldat = netdev_priv(ndev); + + unregister_netdev(ndev); + platform_set_drvdata(pdev, NULL); + dma_free_coherent(&pldat->pdev->dev, pldat->dma_buff_size, + (void *) pldat->dma_buff_base_v, (dma_addr_t) pldat->dma_buff_base_p); + free_irq(ndev->irq, ndev); + iounmap(pldat->net_base); + clk_disable(pldat->clk); + clk_put(pldat->clk); + free_netdev(ndev); + + return 0; +} + +static int lpc32xx_net_drv_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct netdata_local *pldat = netdev_priv(ndev); + + if (ndev) + { + if (netif_running(ndev)) + { + netif_device_detach(ndev); + __lpc32xx_net_shutdown(pldat); + clk_disable(pldat->clk); + } + } + + return 0; +} + +static int lpc32xx_net_drv_resume(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct netdata_local *pldat; + + if (ndev) + { + if (netif_running(ndev)) + { + pldat = netdev_priv(ndev); + + /* Enable interface clock */ + clk_enable(pldat->clk); + + /* Reset and initialize */ + __lpc32xx_eth_reset(pldat); + __lpc32xx_eth_init(pldat); + + netif_device_attach(ndev); + } + } + + return 0; +} + +static struct platform_driver lpc32xx_net_driver = { + .probe = lpc32xx_net_drv_probe, + .remove = __devexit_p(lpc32xx_net_drv_remove), + .suspend = lpc32xx_net_drv_suspend, + .resume = lpc32xx_net_drv_resume, + .driver = { + .name = MODNAME, + }, +}; + +static int __init lpc32xx_net_init(void) +{ + return platform_driver_register(&lpc32xx_net_driver); +} + +static void __exit lpc32xx_net_cleanup(void) +{ + platform_driver_unregister(&lpc32xx_net_driver); +} + +module_init(lpc32xx_net_init); +module_exit(lpc32xx_net_cleanup); + +MODULE_AUTHOR("Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +static char rtc_name[] = "rtc-lpc32xx"; + +struct lpc32xx_rtc_priv +{ + void __iomem *rtc_base; + int irq; + int alarm_enabled; + struct rtc_device *rtc; + spinlock_t lock; +}; + +static unsigned long epoch = 1970; /* Jan 1 1970 00:00:00 */ + +static inline unsigned long read_seconds(u32 iobase) +{ + return __raw_readl(RTC_UCOUNT(iobase)); +} + +static inline void write_seconds(u32 iobase, unsigned long sec) +{ + u32 tmp; + + /* Stop counter first */ + tmp = __raw_readl(RTC_CTRL(iobase)); + tmp |= RTC_CNTR_DIS; + __raw_writel(tmp, RTC_CTRL(iobase)); + + __raw_writel(sec, RTC_UCOUNT(iobase)); + __raw_writel((0xFFFFFFFF - sec), RTC_DCOUNT(iobase)); + + /* Restart counter */ + tmp &= ~RTC_CNTR_DIS; + __raw_writel(tmp, RTC_CTRL(iobase)); + + /* Set key so boot ROM won't clear RTC on reset */ + __raw_writel(RTC_KEY_ONSW_LOADVAL, RTC_KEY(iobase)); +} + +static void lpc32xx_rtc_release(struct device *dev) +{ + u32 reg; + struct platform_device *pdev = to_platform_device(dev); + struct lpc32xx_rtc_priv *lpc32xx_rtc_dat = platform_get_drvdata(pdev); + + spin_lock_irq(&lpc32xx_rtc_dat->lock); + + /* Disable RTC match interrupt */ + reg = __raw_readl(RTC_CTRL(lpc32xx_rtc_dat->rtc_base)); + reg &= ~RTC_MATCH0_EN; + __raw_writel(reg, RTC_CTRL(lpc32xx_rtc_dat->rtc_base)); + + spin_unlock_irq(&lpc32xx_rtc_dat->lock); + + /* Disable RTC interrupt in interrupt controller */ + disable_irq(lpc32xx_rtc_dat->irq); +} + +static int lpc32xx_rtc_read_time(struct device *dev, struct rtc_time *time) +{ + unsigned long epoch_sec, elapsed_sec; + struct platform_device *pdev = to_platform_device(dev); + struct lpc32xx_rtc_priv *lpc32xx_rtc_dat = platform_get_drvdata(pdev); + + epoch_sec = mktime(epoch, 1, 1, 0, 0, 0); + elapsed_sec = read_seconds((u32) lpc32xx_rtc_dat->rtc_base); + + rtc_time_to_tm(epoch_sec + elapsed_sec, time); + + return 0; +} + +static int lpc32xx_rtc_set_time(struct device *dev, struct rtc_time *time) +{ + unsigned long epoch_sec, current_sec; + struct platform_device *pdev = to_platform_device(dev); + struct lpc32xx_rtc_priv *lpc32xx_rtc_dat = platform_get_drvdata(pdev); + + epoch_sec = mktime(epoch, 1, 1, 0, 0, 0); + current_sec = mktime(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday, + time->tm_hour, time->tm_min, time->tm_sec); + + spin_lock_irq(&lpc32xx_rtc_dat->lock); + write_seconds((u32) lpc32xx_rtc_dat->rtc_base, (current_sec - epoch_sec)); + spin_unlock_irq(&lpc32xx_rtc_dat->lock); + + return 0; +} + +static int lpc32xx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) +{ + unsigned long alarmsecs; + struct rtc_time *time = &wkalrm->time; + struct platform_device *pdev = to_platform_device(dev); + struct lpc32xx_rtc_priv *lpc32xx_rtc_dat = platform_get_drvdata(pdev); + + /* Read alarm match register */ + alarmsecs = __raw_readl(RTC_MATCH0(lpc32xx_rtc_dat->rtc_base)); + wkalrm->enabled = lpc32xx_rtc_dat->alarm_enabled; + + rtc_time_to_tm(alarmsecs, time); + + return 0; +} + +static int lpc32xx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) +{ + unsigned long alarmsecs; + u32 tmp; + struct rtc_time *time = &wkalrm->time; + struct platform_device *pdev = to_platform_device(dev); + struct lpc32xx_rtc_priv *lpc32xx_rtc_dat = platform_get_drvdata(pdev); + + alarmsecs = mktime(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday, + time->tm_hour, time->tm_min, time->tm_sec); + + spin_lock_irq(&lpc32xx_rtc_dat->lock); + + if (lpc32xx_rtc_dat->alarm_enabled) + { + disable_irq(lpc32xx_rtc_dat->irq); + + tmp = __raw_readl(RTC_CTRL(lpc32xx_rtc_dat->rtc_base)); + tmp &= ~RTC_MATCH0_EN; + __raw_writel(tmp, RTC_CTRL(lpc32xx_rtc_dat->rtc_base)); + } + + __raw_writel(alarmsecs, RTC_MATCH0(lpc32xx_rtc_dat->rtc_base)); + lpc32xx_rtc_dat->alarm_enabled = wkalrm->enabled; + + if (wkalrm->enabled) + { + enable_irq(lpc32xx_rtc_dat->irq); + + tmp = __raw_readl(RTC_CTRL(lpc32xx_rtc_dat->rtc_base)); + tmp |= RTC_MATCH0_EN; + __raw_writel(tmp, RTC_CTRL(lpc32xx_rtc_dat->rtc_base)); + } + + spin_unlock_irq(&lpc32xx_rtc_dat->lock); + + return 0; +} + +static int lpc32xx_rtc_proc(struct device *dev, struct seq_file *seq) +{ + struct platform_device *pdev = to_platform_device(dev); + struct lpc32xx_rtc_priv *lpc32xx_rtc_dat = platform_get_drvdata(pdev); + u32 tmp; + + tmp = __raw_readl(RTC_CTRL(lpc32xx_rtc_dat->rtc_base)); + seq_printf(seq, "Alarm_IRQ\t: %s\n", + (tmp & RTC_MATCH0_EN) ? "yes" : "no"); + + return 0; +} + +static int lpc32xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +{ + struct platform_device *pdev = to_platform_device(dev); + struct lpc32xx_rtc_priv *lpc32xx_rtc_dat = platform_get_drvdata(pdev); + + switch (cmd) { + case RTC_AIE_ON: + spin_lock_irq(&lpc32xx_rtc_dat->lock); + + if (!lpc32xx_rtc_dat->alarm_enabled) + { + enable_irq(lpc32xx_rtc_dat->irq); + lpc32xx_rtc_dat->alarm_enabled = 1; + } + + spin_unlock_irq(&lpc32xx_rtc_dat->lock); + break; + + case RTC_AIE_OFF: + spin_lock_irq(&lpc32xx_rtc_dat->lock); + + if (lpc32xx_rtc_dat->alarm_enabled) + { + disable_irq(lpc32xx_rtc_dat->irq); + lpc32xx_rtc_dat->alarm_enabled = 0; + } + + spin_unlock_irq(&lpc32xx_rtc_dat->lock); + break; + + case RTC_PIE_ON: + enable_irq(lpc32xx_rtc_dat->irq); + break; + + case RTC_PIE_OFF: + disable_irq(lpc32xx_rtc_dat->irq); + break; + + case RTC_IRQP_READ: + return put_user(1, (unsigned long __user *)arg); + break; + + case RTC_IRQP_SET: + /* Only 1Hz is supported */ + if (arg != 1) + return -EINVAL; + break; + + case RTC_EPOCH_READ: + return put_user(epoch, (unsigned long __user *)arg); + + case RTC_EPOCH_SET: + /* Doesn't support before 1900 */ + if (arg < 1900) + return -EINVAL; + epoch = arg; + break; + + default: + return -ENOIOCTLCMD; + } + + return 0; +} + +static irqreturn_t lpc32xx_rtc_alarm_interrupt(int irq, void *dev) +{ + u32 tmp; + struct lpc32xx_rtc_priv *lpc32xx_rtc_dat = (struct lpc32xx_rtc_priv *) dev; + + spin_lock(&lpc32xx_rtc_dat->lock); + + /* If the alarm isn't disabled, the match will keep occuring, so disable + it now */ + tmp = __raw_readl(RTC_CTRL(lpc32xx_rtc_dat->rtc_base)); + tmp &= ~RTC_MATCH0_EN; + __raw_writel(tmp, RTC_CTRL(lpc32xx_rtc_dat->rtc_base)); + + /* Clear match event */ + __raw_writel(RTC_MATCH0_INT_STS, RTC_INTSTAT(lpc32xx_rtc_dat->rtc_base)); + + /* Alarm event */ + rtc_update_irq(lpc32xx_rtc_dat->rtc, 1, RTC_AF); + + spin_unlock(&lpc32xx_rtc_dat->lock); + + return IRQ_HANDLED; +} + +static const struct rtc_class_ops lpc32xx_rtc_ops = { + .release = lpc32xx_rtc_release, + .ioctl = lpc32xx_rtc_ioctl, + .read_time = lpc32xx_rtc_read_time, + .set_time = lpc32xx_rtc_set_time, + .read_alarm = lpc32xx_rtc_read_alarm, + .set_alarm = lpc32xx_rtc_set_alarm, + .proc = lpc32xx_rtc_proc, +}; + +static int __devinit lpc32xx_rtc_probe(struct platform_device *pdev) +{ + struct resource *res; + struct lpc32xx_rtc_priv *lpc32xx_rtc_dat = NULL; + int retval; + u32 tmp; + + /* Get resources */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + { + retval = -EBUSY; + goto errout; + } + + /* Allocate private driver data */ + lpc32xx_rtc_dat = kzalloc(sizeof(struct lpc32xx_rtc_priv), GFP_KERNEL); + if (unlikely(!lpc32xx_rtc_dat)) + { + retval = -ENOMEM; + goto errout; + } + + /* Save resources */ + lpc32xx_rtc_dat->rtc_base = ioremap(res->start, res->end - res->start + 1); + if (!lpc32xx_rtc_dat->rtc_base) + { + retval = -EBUSY; + goto errout; + } + + lpc32xx_rtc_dat->rtc = rtc_device_register(rtc_name, &pdev->dev, + &lpc32xx_rtc_ops, THIS_MODULE); + if (IS_ERR(lpc32xx_rtc_dat->rtc)) + { + retval = PTR_ERR(lpc32xx_rtc_dat->rtc); + goto errout; + } + + /* Setup RTC */ + spin_lock_irq(&lpc32xx_rtc_dat->lock); + tmp = __raw_readl(RTC_CTRL(lpc32xx_rtc_dat->rtc_base)); + tmp &= ~(RTC_SW_RESET | RTC_CNTR_DIS); + __raw_writel(tmp, RTC_CTRL(lpc32xx_rtc_dat->rtc_base)); + __raw_writel(RTC_MATCH0_INT_STS, RTC_INTSTAT(lpc32xx_rtc_dat->rtc_base)); + __raw_writel(RTC_KEY_ONSW_LOADVAL, RTC_KEY(lpc32xx_rtc_dat->rtc_base)); + spin_unlock_irq(&lpc32xx_rtc_dat->lock); + + /* Get interrupt */ + lpc32xx_rtc_dat->irq = platform_get_irq(pdev, 0); + if ((lpc32xx_rtc_dat->irq < 0) || (lpc32xx_rtc_dat->irq >= NR_IRQS)) + { + retval = -EINVAL; + goto errout; + } + + retval = request_irq(lpc32xx_rtc_dat->irq, lpc32xx_rtc_alarm_interrupt, + IRQF_DISABLED, "rtcalarm", lpc32xx_rtc_dat); + if (retval < 0) + { + goto err_free_irq; + } + + platform_set_drvdata(pdev, lpc32xx_rtc_dat); + disable_irq(lpc32xx_rtc_dat->irq); + +#if defined(CONFIG_RTC_DEBUG) + printk(KERN_INFO "rtc: %s initialized\n", rtc_name); + printk(KERN_INFO "rtc: Using IO range 0x%08x to 0x%08x\n", + res->start, res->end); + printk(KERN_INFO "rtc: Alarm mapped on IRQ %d\n", lpc32xx_rtc_dat->irq); +#endif + + return 0; + +err_free_irq: + free_irq(lpc32xx_rtc_dat->irq, pdev); + +errout: +#if defined(CONFIG_RTC_DEBUG) + printk(KERN_ERR "%s: Error initializing RTC\n", rtc_name); +#endif + + if (lpc32xx_rtc_dat->rtc) + { + rtc_device_unregister(lpc32xx_rtc_dat->rtc); + } + if (lpc32xx_rtc_dat) + { + if (lpc32xx_rtc_dat->rtc_base) + { + iounmap(lpc32xx_rtc_dat->rtc_base); + } + + kfree(lpc32xx_rtc_dat); + } + + return retval; +} + +static int __devexit lpc32xx_rtc_remove(struct platform_device *pdev) +{ + struct lpc32xx_rtc_priv *lpc32xx_rtc_dat; + + lpc32xx_rtc_dat = platform_get_drvdata(pdev); + if (lpc32xx_rtc_dat->rtc) + { + rtc_device_unregister(lpc32xx_rtc_dat->rtc); + } + + platform_set_drvdata(pdev, NULL); + + if (lpc32xx_rtc_dat) + { + free_irq(lpc32xx_rtc_dat->irq, pdev); + if (lpc32xx_rtc_dat->rtc_base) + { + iounmap(lpc32xx_rtc_dat->rtc_base); + } + + kfree(lpc32xx_rtc_dat); + } + + return 0; +} + +static struct platform_driver lpc32xx_rtc_driver = { + .probe = lpc32xx_rtc_probe, + .remove = __devexit_p(lpc32xx_rtc_remove), + .driver = { + .name = rtc_name, + .owner = THIS_MODULE, + }, +}; + +static int __init lpc32xx_rtc_init(void) +{ + return platform_driver_register(&lpc32xx_rtc_driver); +} + +static void __exit lpc32xx_rtc_exit(void) +{ + platform_driver_unregister(&lpc32xx_rtc_driver); +} + +module_init(lpc32xx_rtc_init); +module_exit(lpc32xx_rtc_exit); + +MODULE_AUTHOR("Kevin Wells +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define MODNAME "lpc32xx_hsuart" +#define REVISION "$Revision: 0.90 $" + +struct lpc32xx_hsuart_port +{ + struct uart_port port; +}; + +#define PASS_LIMIT 128 + +#define LPC32XX_TTY_NAME "ttyTX" +#define LPC32XX_TTY_MINOR_START 196 +#define LPC32XX_TTY_MAJOR 204 +#define MAX_PORTS 3 +static struct lpc32xx_hsuart_port lpc32xx_hs_ports[MAX_PORTS]; +static struct uart_driver lpc32xx_hs_reg = { + .owner = THIS_MODULE, + .driver_name = MODNAME, + .dev_name = LPC32XX_TTY_NAME, + .major = LPC32XX_TTY_MAJOR, + .minor = LPC32XX_TTY_MINOR_START, + .nr = MAX_PORTS, + .cons = NULL, +}; +static int uarts_registered = 0; +static void serial_lpc32xx_stop_tx(struct uart_port *port); + +static unsigned int __serial_get_clock_div(unsigned long uartclk, + unsigned long rate) +{ + u32 div, goodrate, hsu_rate, l_hsu_rate, brate, erate, erate_diff; + u32 erate_sdiff; + + /* Find the closest divider to get the desired clock rate */ + div = uartclk / rate; + hsu_rate = (div / 14) - 1; + if (hsu_rate != 0) + { + hsu_rate--; + } + + /* Tweak divider */ + goodrate = l_hsu_rate = hsu_rate + 2; + erate_sdiff = 0xFFFFFFFF; + while (hsu_rate < l_hsu_rate) + { + erate = uartclk / ((hsu_rate + 1) * 14); + brate = uartclk / ((goodrate + 1) * 14); + if (brate > erate) + { + erate_diff = brate - erate; + } + else + { + erate_diff = erate - brate; + } + + if (erate_sdiff > erate_diff) + { + erate_sdiff = erate_diff; + goodrate = hsu_rate; + } + + hsu_rate++; + } + if (hsu_rate > 0xFF) + { + hsu_rate = 0xFF; + } + + return goodrate; +} + +static void __serial_uart_flush(struct uart_port *port) +{ + u32 tmp; + int cnt = 0; + + while ((__raw_readl(HSUART_LEVEL(port->membase)) > 0) && + (cnt++ < PASS_LIMIT)) + { + tmp = __raw_readl(HSUART_FIFO(port->membase)); + } +} + +static void __serial_lpc32xx_rx(struct uart_port *port) +{ + struct tty_struct *tty = port->info->port.tty; + unsigned int tmp, flag; + + /* Read data from FIFO and push into terminal */ + while (__raw_readl(HSUART_LEVEL(port->membase)) > 0) + { + tmp = __raw_readl(HSUART_FIFO(port->membase)); + flag = TTY_NORMAL; + port->icount.rx++; + + if (tmp & HSU_ERROR_DATA) + { + /* Framing error */ + __raw_writel(HSU_FE_INT, HSUART_IIR(port->membase)); + port->icount.frame++; + flag = TTY_FRAME; + tty_insert_flip_char (port->info->port.tty, 0, TTY_FRAME); + tty_schedule_flip (port->info->port.tty); + } + + tty_insert_flip_char (port->info->port.tty, (tmp & 0xFF), flag); + } + + tty_flip_buffer_push(tty); +} + +static void __serial_lpc32xx_tx(struct uart_port *port) +{ + struct circ_buf *xmit = &port->info->xmit; + + if (port->x_char) + { + __raw_writel((u32) port->x_char, HSUART_FIFO(port->membase)); + port->icount.tx++; + port->x_char = 0; + return; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) + { + goto exit_tx; + } + + /* Transfer data */ + while (HSU_TX_LEV(__raw_readl(HSUART_LEVEL(port->membase))) < 64) + { + __raw_writel((u32) xmit->buf[xmit->tail], + HSUART_FIFO(port->membase)); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + if (uart_circ_empty(xmit)) + break; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + { + uart_write_wakeup(port); + } + +exit_tx: + if (uart_circ_empty(xmit)) + { + serial_lpc32xx_stop_tx(port); + } +} + +static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + u32 status; + + spin_lock(&port->lock); + + /* Read UART status and clear latched interrupts */ + status = __raw_readl(HSUART_IIR(port->membase)); + __raw_writel((HSU_BRK_INT | HSU_RX_OE_INT | HSU_FE_INT), + HSUART_IIR(port->membase)); + + if (status & HSU_BRK_INT) + { + /* Break received */ + __raw_writel(HSU_BRK_INT, HSUART_IIR(port->membase)); + port->icount.brk++; + uart_handle_break(port); + } + + if (status & HSU_RX_OE_INT) + { + /* Receive FIFO overrun */ + __raw_writel(HSU_RX_OE_INT, HSUART_IIR(port->membase)); + port->icount.overrun++; + tty_insert_flip_char (port->info->port.tty, 0, TTY_OVERRUN); + tty_schedule_flip (port->info->port.tty); + } + + /* Data received? */ + if (status & (HSU_RX_TIMEOUT_INT | HSU_RX_TRIG_INT)) + { + __serial_lpc32xx_rx(port); + } + + /* Transmit data request? */ + if ((status & HSU_TX_INT) && (!uart_tx_stopped(port))) + { + __serial_lpc32xx_tx(port); + } + + spin_unlock(&port->lock); + + return IRQ_HANDLED; +} + +static unsigned int serial_lpc32xx_tx_empty(struct uart_port *port) +{ + unsigned int ret = 0; + + if (HSU_TX_LEV(__raw_readl(HSUART_LEVEL(port->membase))) == 0) + { + /* TX FIFO is empty */ + ret = TIOCSER_TEMT; + } + + return ret; +} + +static void serial_lpc32xx_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + /* No signals are supported on HS UARTs */ +} + +static unsigned int serial_lpc32xx_get_mctrl(struct uart_port *port) +{ + /* No signals are supported on HS UARTs */ + return (TIOCM_CAR | TIOCM_DSR | TIOCM_CTS); +} + +static void serial_lpc32xx_stop_tx(struct uart_port *port) +{ + u32 tmp; + + /* Stop TX interrrupt */ + tmp = __raw_readl(HSUART_CTRL(port->membase)); + tmp &= ~HSU_TX_INT_EN; + __raw_writel(tmp, HSUART_CTRL(port->membase)); +} + +static void serial_lpc32xx_start_tx(struct uart_port *port) +{ + u32 tmp; + + /* Start TX interrrupt */ + __serial_lpc32xx_tx(port); + tmp = __raw_readl(HSUART_CTRL(port->membase)); + tmp |= HSU_TX_INT_EN; + __raw_writel(tmp, HSUART_CTRL(port->membase)); +} + +static void serial_lpc32xx_stop_rx(struct uart_port *port) +{ + u32 tmp; + + tmp = __raw_readl(HSUART_CTRL(port->membase)); + tmp &= ~(HSU_RX_INT_EN | HSU_ERR_INT_EN); + __raw_writel(tmp, HSUART_CTRL(port->membase)); + + __raw_writel((HSU_BRK_INT | HSU_RX_OE_INT | HSU_FE_INT), + HSUART_IIR(port->membase)); +} + +static void serial_lpc32xx_enable_ms(struct uart_port *port) +{ + /* Modem status is not supported */ +} + +static void serial_lpc32xx_break_ctl(struct uart_port *port, int break_state) +{ + unsigned long flags; + u32 tmp; + + spin_lock_irqsave(&port->lock, flags); + tmp = __raw_readl(HSUART_CTRL(port->membase)); + if (break_state != 0) + { + /* Send break */ + tmp |= HSU_BREAK; + } + else + { + tmp &= ~HSU_BREAK; + } + __raw_writel(tmp, HSUART_CTRL(port->membase)); + spin_unlock_irqrestore(&port->lock, flags); +} + +static int serial_lpc32xx_startup(struct uart_port *port) +{ + int retval; + u32 tmp; + + /* Empty FIFO */ + __serial_uart_flush(port); + + /* Clear latched interrupt states */ + __raw_writel((HSU_TX_INT | HSU_FE_INT | HSU_BRK_INT | HSU_RX_OE_INT), + HSUART_IIR(port->membase)); + + /* Setup initial rate to slowest speed */ + __raw_writel(0xFF, HSUART_RATE(port->membase)); + + /* Set receiver timeout, HSU offset of 20, no break, no interrupts, + and default FIFO trigger levels */ + tmp = HSU_TX_TL8B | HSU_RX_TL32B | HSU_OFFSET(20) | HSU_TMO_INACT_4B; + __raw_writel(tmp, HSUART_CTRL(port->membase)); + + retval = request_irq(port->irq, serial_lpc32xx_interrupt, + 0, MODNAME, port); + if (retval) + { + return retval; + } + + /* Enable receive interrupts */ + __raw_writel((tmp | HSU_RX_INT_EN | HSU_ERR_INT_EN), + HSUART_CTRL(port->membase)); + + return 0; +} + +static void serial_lpc32xx_shutdown(struct uart_port *port) +{ + u32 tmp; + + /* Disable interrupts and break */ + tmp = HSU_TX_TL8B | HSU_RX_TL32B | HSU_OFFSET(20) | HSU_TMO_INACT_4B; + __raw_writel(tmp, HSUART_CTRL(port->membase)); + + free_irq(port->irq, port); +} + +static void serial_lpc32xx_set_termios(struct uart_port *port, + struct ktermios *termios, struct ktermios *old) +{ + unsigned long flags; + unsigned int baud, quot; + u32 tmp; + + /* The high speed UART only supports 8-bit operation with 1 stop bit and + no parity, so there isn't really a lot to do here. Clock speed is + supported, so set it to the desired rate */ + + /* Always 8-bit, no parity, 1 stop bit */ + termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD); + termios->c_cflag |= CS8; + + /* No support for modem control lines */ + termios->c_cflag &= ~(HUPCL | CMSPAR | CLOCAL | CRTSCTS); + + /* Compute block divider */ + baud = uart_get_baud_rate(port, termios, old, 0, (port->uartclk / 14)); + quot = __serial_get_clock_div(port->uartclk, baud); + + spin_lock_irqsave(&port->lock, flags); + + /* Ignore characters? */ + tmp = __raw_readl(HSUART_CTRL(port->membase)); + if ((termios->c_cflag & CREAD) == 0) + { + /* Disable UART interrupts */ + tmp &= ~(HSU_RX_INT_EN | HSU_ERR_INT_EN); + } + else + { + /* Enable UART interrupts */ + tmp |= HSU_RX_INT_EN | HSU_ERR_INT_EN; + } + __raw_writel(tmp, HSUART_CTRL(port->membase)); + + /* Setup baud rate */ + __raw_writel((quot - 1), HSUART_RATE(port->membase)); + + /* Update the per-port timeout */ + uart_update_timeout(port, termios->c_cflag, baud); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *serial_lpc32xx_type(struct uart_port *port) +{ + return MODNAME; +} + +static void serial_lpc32xx_release_port(struct uart_port *port) +{ + if ((port->iotype == UPIO_MEM32) && (port->mapbase)) + { + if (port->flags & UPF_IOREMAP) + { + iounmap(port->membase); + port->membase = NULL; + } + + release_mem_region(port->mapbase, SZ_4K); + } +} + +static int serial_lpc32xx_request_port(struct uart_port *port) +{ + int ret = -ENODEV; + + if ((port->iotype == UPIO_MEM32) && (port->mapbase)) + { + ret = 0; + + if (!request_mem_region(port->mapbase, SZ_4K, MODNAME)) + { + ret = -EBUSY; + } + else if (port->flags & UPF_IOREMAP) + { + port->membase = ioremap(port->mapbase, SZ_4K); + if (!port->membase) + { + release_mem_region(port->mapbase, SZ_4K); + ret = -ENOMEM; + } + } + } + + return ret; +} + +static void serial_lpc32xx_config_port(struct uart_port *port, int uflags) +{ + int ret; + u32 tmp; + + /* + * Find the region that we can probe for. This in turn + * tells us whether we can probe for the type of port. + */ + ret = serial_lpc32xx_request_port(port); + if (ret < 0) + return; + port->type = PORT_UART00; + port->fifosize = 64; + + /* Empty FIFO */ + __serial_uart_flush(port); + + /* Clear latched interrupt states */ + __raw_writel((HSU_TX_INT | HSU_FE_INT | HSU_BRK_INT | HSU_RX_OE_INT), + HSUART_IIR(port->membase)); + + /* Setup initial rate to slowest speed */ + __raw_writel(0xFF, HSUART_RATE(port->membase)); + + /* Set receiver timeout, HSU offset of 20, no break, no interrupts, + and default FIFO trigger levels */ + tmp = HSU_TX_TL8B | HSU_RX_TL32B | HSU_OFFSET(20) | HSU_TMO_INACT_4B; + __raw_writel(tmp, HSUART_CTRL(port->membase)); +} + +static int serial_lpc32xx_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + int ret = 0; + + if (ser->type != PORT_UART00) + ret = -EINVAL; + + return ret; +} + +static struct uart_ops serial_lpc32xx_pops = +{ + .tx_empty = serial_lpc32xx_tx_empty, + .set_mctrl = serial_lpc32xx_set_mctrl, + .get_mctrl = serial_lpc32xx_get_mctrl, + .stop_tx = serial_lpc32xx_stop_tx, + .start_tx = serial_lpc32xx_start_tx, + .stop_rx = serial_lpc32xx_stop_rx, + .enable_ms = serial_lpc32xx_enable_ms, + .break_ctl = serial_lpc32xx_break_ctl, + .startup = serial_lpc32xx_startup, + .shutdown = serial_lpc32xx_shutdown, + .set_termios = serial_lpc32xx_set_termios, + .type = serial_lpc32xx_type, + .release_port = serial_lpc32xx_release_port, + .request_port = serial_lpc32xx_request_port, + .config_port = serial_lpc32xx_config_port, + .verify_port = serial_lpc32xx_verify_port, +}; + +/* + * Register a set of serial devices attached to a platform device + */ +static int __devinit serial_hs_lpc32xx_probe(struct platform_device *pdev) +{ + struct uart_port *p = pdev->dev.platform_data; + struct lpc32xx_hsuart_port *pdr; + int i, ret = 0; + + uarts_registered = 0; + for (i = 0; p && (p->flags != 0); i++) + { + pdr = &lpc32xx_hs_ports[i]; + memset(pdr, 0, sizeof(struct lpc32xx_hsuart_port)); + + pdr->port.iotype = p->iotype; + pdr->port.membase = p->membase; + pdr->port.mapbase = p->mapbase; + pdr->port.irq = p->irq; + pdr->port.uartclk = p->uartclk; + pdr->port.regshift = p->regshift; + pdr->port.flags = p->flags | UPF_FIXED_PORT; + pdr->port.dev = &pdev->dev; + pdr->port.ops = &serial_lpc32xx_pops; + pdr->port.line = p->line; + spin_lock_init(&pdr->port.lock); + + uart_add_one_port(&lpc32xx_hs_reg, &pdr->port); + p++; + uarts_registered++; + } + + return ret; +} + +/* + * Remove serial ports registered against a platform device. + */ +static int __devexit serial_hs_lpc32xx_remove(struct platform_device *pdev) +{ + struct lpc32xx_hsuart_port *p; + int i; + + for (i = 0; i < uarts_registered; i++) + { + p = &lpc32xx_hs_ports[i]; + + if (p->port.dev == &pdev->dev) + { + uart_remove_one_port(&lpc32xx_hs_reg, &p->port); + } + } + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver serial_hs_lpc32xx_driver = +{ + .probe = serial_hs_lpc32xx_probe, + .remove = __devexit_p(serial_hs_lpc32xx_remove), + /* Suspend and resume are not needed, as the UART autoclocks */ + .driver = + { + .name = MODNAME, + .owner = THIS_MODULE, + }, +}; + +static int __init lpc32xx_hsuart_init(void) +{ + int ret; + + ret = uart_register_driver(&lpc32xx_hs_reg); + if (ret == 0) + { + ret = platform_driver_register(&serial_hs_lpc32xx_driver); + if (ret) + { + uart_unregister_driver(&lpc32xx_hs_reg); + } + } + + return ret; +} + +static void __exit lpc32xx_hsuart_exit(void) +{ + platform_driver_unregister(&serial_hs_lpc32xx_driver); + uart_unregister_driver(&lpc32xx_hs_reg); +} + +module_init (lpc32xx_hsuart_init); +module_exit (lpc32xx_hsuart_exit); + +MODULE_AUTHOR ("Kevin Wells (kevin.wells@nxp.com)"); +MODULE_DESCRIPTION ("NXP LPC32XX High speed UART driver"); +MODULE_LICENSE ("GPL"); + diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/drivers/serial/Kconfig linux-2.6.27.8/drivers/serial/Kconfig --- linux-2.6.27.8-base/drivers/serial/Kconfig 2009-01-08 11:44:01.000000000 -0800 +++ linux-2.6.27.8/drivers/serial/Kconfig 2009-01-08 12:02:03.000000000 -0800 @@ -974,6 +974,13 @@ If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330 and you want to use serial console, say Y. Otherwise, say N. +config SERIAL_HS_LPC32XX + tristate "LPC32xx high serial port support" + depends on ARCH_LPC32XX + select SERIAL_CORE + help + Support for the LPC32XX high speed serial ports + config SERIAL_CORE tristate diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/drivers/serial/Makefile linux-2.6.27.8/drivers/serial/Makefile --- linux-2.6.27.8-base/drivers/serial/Makefile 2009-01-08 11:44:01.000000000 -0800 +++ linux-2.6.27.8/drivers/serial/Makefile 2009-01-08 12:02:03.000000000 -0800 @@ -69,3 +69,5 @@ obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o obj-$(CONFIG_SERIAL_QE) += ucc_uart.o +obj-$(CONFIG_SERIAL_HS_LPC32XX) += hs_serial_lpc32xx.o + diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/drivers/spi/Kconfig linux-2.6.27.8/drivers/spi/Kconfig --- linux-2.6.27.8-base/drivers/spi/Kconfig 2009-01-08 11:43:32.000000000 -0800 +++ linux-2.6.27.8/drivers/spi/Kconfig 2009-01-08 12:02:03.000000000 -0800 @@ -204,6 +204,13 @@ See the "OPB Serial Peripheral Interface (SPI) (v1.00e)" Product Specification document (DS464) for hardware details. +config SPI_LPC32XX + tristate "LPC32XX SPI controller" + depends on SPI_MASTER && ARCH_LPC32XX + help + SPI controller for the LPC32XX device using the SSP + controllers + # # Add new SPI master controllers in alphabetical order above this line # diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/drivers/spi/Makefile linux-2.6.27.8/drivers/spi/Makefile --- linux-2.6.27.8-base/drivers/spi/Makefile 2009-01-08 11:43:32.000000000 -0800 +++ linux-2.6.27.8/drivers/spi/Makefile 2009-01-08 12:02:03.000000000 -0800 @@ -28,6 +28,7 @@ obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o obj-$(CONFIG_SPI_TXX9) += spi_txx9.o obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o +obj-$(CONFIG_SPI_LPC32XX) += spi_lpc32xx.o obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.o # ... add above this line ... diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/drivers/spi/spi_lpc32xx.c linux-2.6.27.8/drivers/spi/spi_lpc32xx.c --- linux-2.6.27.8-base/drivers/spi/spi_lpc32xx.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/drivers/spi/spi_lpc32xx.c 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,649 @@ +/* + * drivers/spi/spi_lpc32xx.c + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 + */ + +#define SSP_DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +struct lpc32xxspi +{ + spinlock_t lock; + struct workqueue_struct *workqueue; + struct work_struct work; + struct list_head queue; + wait_queue_head_t waitq; + struct spi_master *master; + struct clk *clk; + void __iomem *membase; + int irq; + int id; + struct lpc32xx_spi_cfg *psspcfg; + u32 current_speed_hz; + u8 current_bits_wd; +}; + +/* + * Default configuration for boards without specific setup + */ +static struct lpc32xx_spi_cfg lpc32xx_stdspi_cfg = +{ + .num_cs = 1, +}; + +static void lpc32xx_spi_prep(struct lpc32xxspi *spidat) +{ + u32 tmp; + + /* Clear and mask SSP interrupts */ + __raw_writel((SSP_ICR_RORIC | SSP_ICR_RTIC), SSP_ICR(spidat->membase)); + __raw_writel(0, SSP_IMSC(spidat->membase)); + + /* Setup default SPI mode */ + __raw_writel((SSP_CR0_DSS(16) | SSP_CR0_FRF_SPI | SSP_CR0_CPOL(0) | + SSP_CR0_CPHA(0) | SSP_CR0_SCR(0)), SSP_CR0(spidat->membase)); + __raw_writel(SSP_CR1_SSP_ENABLE, SSP_CR1(spidat->membase)); + __raw_writel(SSP_CPSR_CPDVSR(2), SSP_CPSR(spidat->membase)); + + /* Flush FIFO */ + while (__raw_readl(SSP_SR(spidat->membase)) & SSP_SR_RNE) + { + tmp = __raw_readl(SSP_DATA(spidat->membase)); + } + + /* Controller stays disabled until a transfer occurs */ +} + +static void lpc32xx_cs_set_state(struct spi_device *spi, unsigned int cs, + unsigned int active, unsigned int delay_ns) +{ + struct lpc32xxspi *spidat = spi_master_get_devdata(spi->master); + int val = (spi->mode & SPI_CS_HIGH) ? active : !active; + + if (spidat->psspcfg->spi_cs_set != NULL) + { + spidat->psspcfg->spi_cs_set(cs, val); + } + + ndelay(delay_ns); +} + +static void lpc32xx_update_spi_clock(struct lpc32xxspi *spidat, u32 speed_hz) +{ + u32 tmp, scr, cpsr, cmp_clk, bus_hz; + + /* Get base clock for this device */ + bus_hz = clk_get_rate(spidat->clk); + + /* speed zero convention is used by some upper layers */ + if ((speed_hz) && (speed_hz > (bus_hz / (0x100 * 0xFF)))) + { + cmp_clk = 0xFFFFFFFF; + cpsr = 2; + scr = 0; + + /* Find best clock dividers to get desired rate */ + while (cmp_clk > speed_hz) + { + cmp_clk = bus_hz / ((scr + 1) * cpsr); + if (cmp_clk > speed_hz) + { + scr++; + if (scr > 0xFF) + { + scr = 0; + cpsr += 2; + } + } + } + } + else + { + /* Use maximum dividers */ + scr = 0xFF; + cpsr = 0xFF; + } + + spidat->current_speed_hz = bus_hz / (cpsr * (scr + 1)); + + tmp = __raw_readl(SSP_CR0(spidat->membase)); + tmp &= ~SSP_CR0_SCR(0xFF); + tmp |= SSP_CR0_SCR(scr); + __raw_writel(tmp, SSP_CR0(spidat->membase)); + __raw_writel(cpsr, SSP_CPSR(spidat->membase)); +} + +static void lpc32xx_update_spi_dwidth(struct lpc32xxspi *spidat, u32 bits_per_word) +{ + u32 tmp; + + tmp = __raw_readl(SSP_CR0(spidat->membase)); + tmp &= ~SSP_CR0_DSS(16); + tmp |= SSP_CR0_DSS(bits_per_word); + __raw_writel(tmp, SSP_CR0(spidat->membase)); + + spidat->current_bits_wd = bits_per_word; +} + +/* the spi->mode bits understood by this driver: */ +#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH) + +static int lpc32xx_spi_setup(struct spi_device *spi) +{ + struct lpc32xxspi *spidat = spi_master_get_devdata(spi->master); + unsigned long flags; + unsigned int bits = spi->bits_per_word; + u32 tmp; + + if (spi->chip_select > spi->master->num_chipselect) + { + dev_dbg(&spi->dev, + "setup: invalid chipselect %u (%u defined)\n", + spi->chip_select, spi->master->num_chipselect); + return -EINVAL; + } + + if (bits == 0) + { + bits = 8; + } + if ((bits < 4) || (bits > 16)) + { + dev_dbg(&spi->dev, + "setup: invalid bits_per_word %u (8 to 16)\n", bits); + return -EINVAL; + } + + if (spi->mode & ~MODEBITS) + { + dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n", + spi->mode & ~MODEBITS); + return -EINVAL; + } + + spin_lock_irqsave(&spidat->lock, flags); + clk_enable(spidat->clk); + + /* Setup CR0 register */ + tmp = SSP_CR0_FRF_SPI; + if (spi->mode & SPI_CPOL) + { + tmp |= SSP_CR0_CPOL(1); + } + if (spi->mode & SPI_CPHA) + { + tmp |= SSP_CR0_CPHA(1); + } + + __raw_writel(tmp, SSP_CR0(spidat->membase)); + lpc32xx_update_spi_dwidth(spidat, bits); + lpc32xx_update_spi_clock(spidat, spi->max_speed_hz); + lpc32xx_cs_set_state(spi, spi->chip_select, 0, 0); + clk_disable(spidat->clk); + spin_unlock_irqrestore(&spidat->lock, flags); + +#if defined (SSP_DEBUG) + dev_dbg(&spi->dev, "SSP (%d) prog rate = %d / " + "actual rate = %d, bits = %d\n", spi->chip_select, + spi->max_speed_hz, spidat->current_speed_hz, spidat->current_bits_wd); +#endif + + return 0; +} + +static irqreturn_t lpc32xx_spi_irq(int irq, void *dev_id) +{ + struct lpc32xxspi *spidat = dev_id; + + /* Disable interrupts for now, do not clear the interrupt states */ + __raw_writel(0, SSP_IMSC(spidat->membase)); + + wake_up(&spidat->waitq); + + return IRQ_HANDLED; +} + +static void lpc32xx_work_one(struct lpc32xxspi *spidat, struct spi_message *m) +{ + struct spi_device *spi = m->spi; + struct spi_transfer *t; + u32 tmp; + unsigned int cs_delay, wsize, cs_change = 1; + int status = 0; + unsigned long flags; + + /* Enable SSP clock and interrupts */ + spin_lock_irqsave(&spidat->lock, flags); + clk_enable(spidat->clk); + enable_irq(spidat->irq); + + /* CS setup/hold/recovery time in nsec */ + cs_delay = 100 + (NSEC_PER_SEC / 2) / spi->max_speed_hz; + + list_for_each_entry (t, &m->transfers, transfer_list) { + const void *txbuf = t->tx_buf; + void *rxbuf = t->rx_buf; + u32 data; + unsigned int tsize, rlen, tlen = t->len; + u32 speed_hz = t->speed_hz ? : spi->max_speed_hz; + u8 bits_per_word = t->bits_per_word ? : spi->bits_per_word; + + bits_per_word = bits_per_word ? : 8; + wsize = bits_per_word >> 3; + + if (spidat->current_speed_hz != speed_hz) + { + lpc32xx_update_spi_clock(spidat, speed_hz); + } + if (spidat->current_bits_wd != bits_per_word) + { + lpc32xx_update_spi_dwidth(spidat, bits_per_word); + } + + /* Number of actual words to transfer (versus bytes) */ + tlen = tlen / wsize; + + /* Make sure FIFO is flushed, clear pending interrupts, and + then enable SSP interface */ + while (__raw_readl(SSP_SR(spidat->membase)) & SSP_SR_RNE) + { + tmp = __raw_readl(SSP_DATA(spidat->membase)); + } + __raw_writel((SSP_ICR_RORIC | SSP_ICR_RTIC), SSP_ICR(spidat->membase)); + tmp = __raw_readl(SSP_CR1(spidat->membase)); + tmp |= SSP_CR1_SSP_ENABLE; + __raw_writel(tmp, SSP_CR1(spidat->membase)); + + /* Assert selected chip select */ + if (cs_change) + { + lpc32xx_cs_set_state(spi, spi->chip_select, 1, cs_delay); + } + cs_change = t->cs_change; + + /* Verify idle state */ + while (__raw_readl(SSP_SR(spidat->membase)) & SSP_SR_BSY) + { + cpu_relax(); + } + + rlen = tlen; + while (rlen) + { + /* Fill TX FIFO */ + if (tlen > 0) + { + if (__raw_readl(SSP_SR(spidat->membase)) & SSP_SR_TFE) + { + tsize = tlen; + if (tsize > (SSP_FIFO_DEPTH_WORDS * wsize)) + { + tsize = SSP_FIFO_DEPTH_WORDS * wsize; + } + tlen -= tsize; + + /* Fill FIFO */ + while (tsize > 0) + { + if (txbuf) + { + data = (wsize == 1) + ? *(const u8 *) txbuf + : *(const u16 *) txbuf; + __raw_writel(data, SSP_DATA(spidat->membase)); + txbuf += wsize; + } + else + { + /* Send dummy data */ + __raw_writel(0x00, SSP_DATA(spidat->membase)); + } + + tsize -= wsize; + } + } + } + + /* Wait for data */ + __raw_writel((SSP_IMSC_RTIM | SSP_IMSC_RXIM), SSP_IMSC(spidat->membase)); + spin_unlock_irqrestore(&spidat->lock, flags); + wait_event(spidat->waitq, + (__raw_readl(SSP_RIS(spidat->membase)) & + (SSP_MIS_RTMIS | SSP_MIS_RXMIS))); + spin_lock_irqsave(&spidat->lock, flags); + + /* Has an overflow occurred? */ + if (unlikely(__raw_readl(SSP_MIS(spidat->membase)) & + SSP_MIS_RORMIS)) + { + lpc32xx_cs_set_state(spi, spi->chip_select, 0, 0); + status = -EIO; + goto exit; + } + + /* Clear other interrupts */ + __raw_writel((SSP_ICR_RORIC | SSP_ICR_RTIC), + SSP_ICR(spidat->membase)); + + /* Is there any data to read? */ + while (__raw_readl(SSP_SR(spidat->membase)) & SSP_SR_RNE) + { + data = __raw_readl(SSP_DATA(spidat->membase)); + if ((rxbuf) && (rlen)) + { + if (wsize == 1) + { + *(u8 *)rxbuf = (u8) data; + } + else + { + *(u16 *)rxbuf = (u16) data; + } + rxbuf += wsize; + } + + rlen -= wsize; + } + } + + m->actual_length += t->len; + if (t->delay_usecs) + { + udelay(t->delay_usecs); + } + + if (!cs_change) + continue; + if (t->transfer_list.next == &m->transfers) + break; + /* sometimes a short mid-message deselect of the chip + * may be needed to terminate a mode or command + */ + lpc32xx_cs_set_state(spi, spi->chip_select, 0, cs_delay); + } + +exit: + spin_unlock_irqrestore(&spidat->lock, flags); + + /* Disable SSP and SSP interrupts, stop SSP clock to save power */ + tmp = __raw_readl(SSP_CR1(spidat->membase)); + tmp &= ~SSP_CR1_SSP_ENABLE; + __raw_writel(tmp, SSP_CR1(spidat->membase)); + disable_irq(spidat->irq); + clk_disable(spidat->clk); + + if (!(status == 0 && cs_change)) + { + lpc32xx_cs_set_state(spi, spi->chip_select, 0, cs_delay); + } + + m->status = status; + m->complete(m->context); +} + +static void lpc32xx_work(struct work_struct *work) +{ + struct lpc32xxspi *spidat = container_of(work, struct lpc32xxspi, work); + unsigned long flags; + + spin_lock_irqsave(&spidat->lock, flags); + + while (!list_empty(&spidat->queue)) + { + struct spi_message *m; + + m = container_of(spidat->queue.next, struct spi_message, queue); + list_del_init(&m->queue); + + spin_unlock_irqrestore(&spidat->lock, flags); + lpc32xx_work_one(spidat, m); + spin_lock_irqsave(&spidat->lock, flags); + } + + spin_unlock_irqrestore(&spidat->lock, flags); +} + + + +static int lpc32xx_spi_transfer(struct spi_device *spi, struct spi_message *m) +{ + struct spi_master *master = spi->master; + struct lpc32xxspi *spidat = spi_master_get_devdata(master); + struct device *controller = spi->master->dev.parent; + struct spi_transfer *t; + unsigned long flags; + + m->actual_length = 0; + + /* check each transfer's parameters */ + list_for_each_entry (t, &m->transfers, transfer_list) + { + u8 bits_per_word = t->bits_per_word ? : spi->bits_per_word; + + bits_per_word = bits_per_word ? : 8; + if ((!t->tx_buf) && (!t->rx_buf) && (t->len)) + { + return -EINVAL; + } + if ((bits_per_word < 4) || (bits_per_word > 16)) + { + return -EINVAL; + } + +#if defined (SSP_DEBUG) + dev_dbg(controller, + " xfer %p: len %u tx %p/%08x rx %p/%08x\n", + t, t->len, t->tx_buf, t->tx_dma, + t->rx_buf, t->rx_dma); +#endif + } + + spin_lock_irqsave(&spidat->lock, flags); + list_add_tail(&m->queue, &spidat->queue); + queue_work(spidat->workqueue, &spidat->work); + spin_unlock_irqrestore(&spidat->lock, flags); + + return 0; +} + +static int __init lpc32xx_spi_probe(struct platform_device *pdev) +{ + struct spi_master *master; + struct lpc32xxspi *spidat; + struct resource *res; + char clkname[16]; + int ret, irq, i; + + /* Get required resources */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + irq = platform_get_irq(pdev, 0); + if ((!res) || (irq < 0) | (irq >= NR_IRQS)) + { + return -EBUSY; + } + + master = spi_alloc_master(&pdev->dev, sizeof(struct lpc32xxspi)); + if (!master) + { + return -ENODEV; + } + spidat = spi_master_get_devdata(master); + platform_set_drvdata(pdev, master); + + /* Save ID for this device */ + spidat->id = pdev->id; + spidat->irq = irq; + spin_lock_init(&spidat->lock); + + INIT_WORK(&spidat->work, lpc32xx_work); + INIT_LIST_HEAD(&spidat->queue); + init_waitqueue_head(&spidat->waitq); + spidat->workqueue = create_singlethread_workqueue(master->dev.parent->bus_id); + if (!spidat->workqueue) + { + ret = -ENOMEM; + goto errout; + } + + /* Generate clock name and get clock */ + snprintf(clkname, 10, "spi%d_ck", spidat->id); + spidat->clk = clk_get(&pdev->dev, clkname); + if (IS_ERR(spidat->clk)) { + ret = -ENODEV; + goto errout_qdel; + } + clk_enable(spidat->clk); + + /* Save IO resources */ + spidat->membase = ioremap(res->start, res->end - res->start + 1); + if (!spidat->membase) + { + ret = -EBUSY; + goto errout2; + } + + ret = request_irq(spidat->irq, lpc32xx_spi_irq, + IRQF_DISABLED, "spiirq", spidat); + if (ret) + { + ret = -EBUSY; + goto errout3; + } + disable_irq(spidat->irq); + + master->bus_num = spidat->id; + master->setup = lpc32xx_spi_setup; + master->transfer = lpc32xx_spi_transfer; + + /* Is a board specific configuration available? */ + spidat->psspcfg = (struct lpc32xx_spi_cfg *) pdev->dev.platform_data; + if (spidat->psspcfg == NULL) + { + spidat->psspcfg = &lpc32xx_stdspi_cfg; + } + if (spidat->psspcfg->num_cs < 1) + { + spidat->psspcfg = &lpc32xx_stdspi_cfg; + } + + master->num_chipselect = spidat->psspcfg->num_cs; + + /* Initialize each chip select and set chip select low */ + for (i = 0; i < spidat->psspcfg->num_cs; i++) + { + if (spidat->psspcfg->spi_cs_setup != NULL) + { + spidat->psspcfg->spi_cs_setup(i); + } + if (spidat->psspcfg->spi_cs_set != NULL) + { + spidat->psspcfg->spi_cs_set(i, 0); + } + } + + /* Initial setup of SPI */ + lpc32xx_spi_prep(spidat); + + /* Keep the SSP clock off until a transfer is performed to save power */ + clk_disable(spidat->clk); + + ret = spi_register_master(master); + if (ret) + { + goto errout4; + } + + return 0; + +errout4: + free_irq(spidat->irq, pdev); +errout3: + iounmap(spidat->membase); +errout2: + clk_disable(spidat->clk); + clk_put(spidat->clk); +errout_qdel: + destroy_workqueue(spidat->workqueue); +errout: + platform_set_drvdata(pdev, NULL); + spi_master_put(master); + + return ret; +} + +static int __devexit lpc32xx_spi_remove(struct platform_device *pdev) +{ + struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); + struct lpc32xxspi *spidat = spi_master_get_devdata(master); + + spi_unregister_master(master); + platform_set_drvdata(pdev, NULL); + + free_irq(spidat->irq, pdev); + + iounmap(spidat->membase); + clk_disable(spidat->clk); + clk_put(spidat->clk); + + destroy_workqueue(spidat->workqueue); + spi_master_put(master); + + return 0; +} + +static struct platform_driver lpc32xx_spi_driver = { + .probe = lpc32xx_spi_probe, + .remove = __devexit_p(lpc32xx_spi_remove), + .driver = { + .name = "spi_lpc32xx", + .owner = THIS_MODULE, + }, +}; + +static int __init lpc32xx_spi_init(void) +{ + return platform_driver_register(&lpc32xx_spi_driver); +} + +static void __exit lpc32xx_spi_exit(void) +{ + platform_driver_unregister(&lpc32xx_spi_driver); +} + +module_init(lpc32xx_spi_init); +module_exit(lpc32xx_spi_exit); + +MODULE_AUTHOR("Kevin Wells #include +#if defined(CONFIG_ARCH_LPC32XX) +#include +#include +#define PNX4008_PWRMAN_BASE CLK_PM_BASE +#define PNX4008_USB_CONFIG_BASE USB_BASE + +#else #include #include #include +#endif #define USB_CTRL IO_ADDRESS(PNX4008_PWRMAN_BASE + 0x64) @@ -174,8 +182,19 @@ i2c_master_send(isp1301_i2c_client, &tmpbuf[0], 2); } +static u16 i2c_read16(u8 subaddr) +{ + u16 data; + + i2c_master_send(isp1301_i2c_client, &subaddr, 1); + i2c_master_recv(isp1301_i2c_client, (u8 *) &data, 2); + + return data; +} + static void isp1301_configure(void) { +#if !defined(CONFIG_ARCH_LPC32XX) /* PNX4008 only supports DAT_SE0 USB mode */ /* PNX4008 R2A requires setting the MAX603 to output 3.6V */ /* Power up externel charge-pump */ @@ -198,6 +217,40 @@ i2c_write(0xFF, ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR); +#else + /* LPC32XX only supports DAT_SE0 USB mode */ + /* This sequence is important */ + + /* Disable transparent UART mode first */ + i2c_write(MC1_UART_EN, (ISP1301_I2C_MODE_CONTROL_1 | + ISP1301_I2C_REG_CLEAR_ADDR)); + + i2c_write(~MC1_SPEED_REG, (ISP1301_I2C_MODE_CONTROL_1 | + ISP1301_I2C_REG_CLEAR_ADDR)); + i2c_write(MC1_SPEED_REG, ISP1301_I2C_MODE_CONTROL_1); + i2c_write(~0, (ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR)); + i2c_write((MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL), + ISP1301_I2C_MODE_CONTROL_2); + i2c_write(~0, (ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR)); + i2c_write(MC1_DAT_SE0, ISP1301_I2C_MODE_CONTROL_1); + i2c_write((OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN), + ISP1301_I2C_OTG_CONTROL_1); + i2c_write((OTG1_DM_PULLUP | OTG1_DP_PULLUP), + (ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR)); + i2c_write(~0, + ISP1301_I2C_INTERRUPT_LATCH | ISP1301_I2C_REG_CLEAR_ADDR); + i2c_write(~0, + ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR); + i2c_write(~0, + ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR); + + /* Enable usb_need_clk clock after transceiver is initialized */ + __raw_writel((__raw_readl(USB_CTRL) | (1 << 22)), USB_CTRL); + + printk(KERN_INFO "ISP1301 Vendor ID : 0x%04x\n", i2c_read16(0x00)); + printk(KERN_INFO "ISP1301 Product ID : 0x%04x\n", i2c_read16(0x02)); + printk(KERN_INFO "ISP1301 Version ID : 0x%04x\n", i2c_read16(0x14)); +#endif } static inline void isp1301_vbus_on(void) @@ -288,6 +341,7 @@ static void pnx4008_set_usb_bits(void) { +#if !defined(CONFIG_ARCH_LPC32XX) start_int_set_falling_edge(SE_USB_OTG_ATX_INT_N); start_int_ack(SE_USB_OTG_ATX_INT_N); start_int_umask(SE_USB_OTG_ATX_INT_N); @@ -311,16 +365,19 @@ start_int_set_rising_edge(SE_USB_AHB_NEED_CLK_INT); start_int_ack(SE_USB_AHB_NEED_CLK_INT); start_int_umask(SE_USB_AHB_NEED_CLK_INT); +#endif } static void pnx4008_unset_usb_bits(void) { +#if !defined(CONFIG_ARCH_LPC32XX) start_int_mask(SE_USB_OTG_ATX_INT_N); start_int_mask(SE_USB_OTG_TIMER_INT); start_int_mask(SE_USB_I2C_INT); start_int_mask(SE_USB_INT); start_int_mask(SE_USB_NEED_CLK_INT); start_int_mask(SE_USB_AHB_NEED_CLK_INT); +#endif } static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev) @@ -354,6 +411,15 @@ err("failed to connect I2C to ISP1301 USB Transceiver"); goto out; } + if (isp1301_i2c_client == NULL) + { + /* Client not found */ + err("I2C slave device not found"); + ret = -ENODEV; + goto out; + } + printk(KERN_INFO "I2C device at address 0x%x", + isp1301_i2c_client->addr); isp1301_configure(); diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/drivers/watchdog/Kconfig linux-2.6.27.8/drivers/watchdog/Kconfig --- linux-2.6.27.8-base/drivers/watchdog/Kconfig 2009-01-08 11:44:12.000000000 -0800 +++ linux-2.6.27.8/drivers/watchdog/Kconfig 2009-01-08 12:02:03.000000000 -0800 @@ -189,6 +189,17 @@ Say N if you are unsure. +config LPC32XX_WATCHDOG + tristate "LPC32XX Watchdog" + depends on ARCH_LPC32XX + help + Say Y here if to include support for the watchdog timer + in the LPC32XX processor. + This driver can be built as a module by choosing M. The module + will be called pnx4008_wdt. + + Say N if you are unsure. + config IOP_WATCHDOG tristate "IOP Watchdog" depends on PLAT_IOP diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/drivers/watchdog/Makefile linux-2.6.27.8/drivers/watchdog/Makefile --- linux-2.6.27.8-base/drivers/watchdog/Makefile 2009-01-08 11:44:12.000000000 -0800 +++ linux-2.6.27.8/drivers/watchdog/Makefile 2009-01-08 12:02:03.000000000 -0800 @@ -37,6 +37,7 @@ obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o +obj-$(CONFIG_LPC32XX_WATCHDOG) += pnx4008_wdt.o obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/drivers/watchdog/pnx4008_wdt.c linux-2.6.27.8/drivers/watchdog/pnx4008_wdt.c --- linux-2.6.27.8-base/drivers/watchdog/pnx4008_wdt.c 2009-01-08 11:44:12.000000000 -0800 +++ linux-2.6.27.8/drivers/watchdog/pnx4008_wdt.c 2009-01-08 12:02:03.000000000 -0800 @@ -113,7 +113,19 @@ __raw_writel(MATCH_INT, WDTIM_INT(wdt_base)); /* the longest pulse period 65541/(13*10^6) seconds ~ 5 ms. */ __raw_writel(0xFFFF, WDTIM_PULSE(wdt_base)); +#if defined (CONFIG_LPC32XX_WATCHDOG) + if (wdt_clk) + { + __raw_writel(heartbeat * clk_get_rate(wdt_clk), + WDTIM_MATCH0(wdt_base)); + } + else + { + __raw_writel(heartbeat * WDOG_COUNTER_RATE, WDTIM_MATCH0(wdt_base)); + } +#else __raw_writel(heartbeat * WDOG_COUNTER_RATE, WDTIM_MATCH0(wdt_base)); +#endif /*enable counter, stop when debugger active */ __raw_writel(COUNT_ENAB | DEBUG_EN, WDTIM_CTRL(wdt_base)); @@ -125,6 +137,7 @@ spin_lock(&io_lock); __raw_writel(0, WDTIM_CTRL(wdt_base)); /*stop counter */ + if (wdt_clk) clk_set_rate(wdt_clk, 0); @@ -307,6 +320,7 @@ clk_put(wdt_clk); wdt_clk = NULL; } + if (wdt_mem) { release_resource(wdt_mem); kfree(wdt_mem); diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/include/linux/amba/clcd.h linux-2.6.27.8/include/linux/amba/clcd.h --- linux-2.6.27.8-base/include/linux/amba/clcd.h 2009-01-08 11:43:22.000000000 -0800 +++ linux-2.6.27.8/include/linux/amba/clcd.h 2009-01-08 12:02:03.000000000 -0800 @@ -21,7 +21,7 @@ #define CLCD_UBAS 0x00000010 #define CLCD_LBAS 0x00000014 -#if !defined(CONFIG_ARCH_VERSATILE) && !defined(CONFIG_ARCH_REALVIEW) +#if !defined(CONFIG_ARCH_VERSATILE) && !defined(CONFIG_ARCH_REALVIEW) && !defined(CONFIG_ARCH_LPC32XX) #define CLCD_IENB 0x00000018 #define CLCD_CNTL 0x0000001c #else diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/include/linux/i2c-pnx.h linux-2.6.27.8/include/linux/i2c-pnx.h --- linux-2.6.27.8-base/include/linux/i2c-pnx.h 2009-01-08 11:43:19.000000000 -0800 +++ linux-2.6.27.8/include/linux/i2c-pnx.h 2009-01-08 12:02:03.000000000 -0800 @@ -21,7 +21,7 @@ int mode; /* Interface mode */ struct completion complete; /* I/O completion */ struct timer_list timer; /* Timeout */ - char * buf; /* Data buffer */ + u8 * buf; /* Data buffer */ int len; /* Length of data buffer */ }; diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/sound/soc/codecs/uda1380.c linux-2.6.27.8/sound/soc/codecs/uda1380.c --- linux-2.6.27.8-base/sound/soc/codecs/uda1380.c 2009-01-08 11:42:37.000000000 -0800 +++ linux-2.6.27.8/sound/soc/codecs/uda1380.c 2009-01-08 12:02:03.000000000 -0800 @@ -119,7 +119,17 @@ return -EIO; } -#define uda1380_reset(c) uda1380_write(c, UDA1380_RESET, 0) +// FIXME +//#define uda1380_reset(c) uda1380_write(c, UDA1380_RESET, 0) +void uda1380_reset(struct snd_soc_codec *codec) { + u8 data[3]; + + data[0] = UDA1380_RESET; + data[1] = 0; + data[2] = 0; + + i2c_master_send(codec->control_data, data, 3); +} /* declarations of ALSA reg_elem_REAL controls */ static const char *uda1380_deemp[] = { diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/sound/soc/Kconfig linux-2.6.27.8/sound/soc/Kconfig --- linux-2.6.27.8-base/sound/soc/Kconfig 2009-01-08 11:42:38.000000000 -0800 +++ linux-2.6.27.8/sound/soc/Kconfig 2009-01-08 12:02:03.000000000 -0800 @@ -31,6 +31,7 @@ source "sound/soc/fsl/Kconfig" source "sound/soc/davinci/Kconfig" source "sound/soc/omap/Kconfig" +source "sound/soc/lpc3xxx/Kconfig" # Supported codecs source "sound/soc/codecs/Kconfig" diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/sound/soc/lpc3xxx/Kconfig linux-2.6.27.8/sound/soc/lpc3xxx/Kconfig --- linux-2.6.27.8-base/sound/soc/lpc3xxx/Kconfig 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/sound/soc/lpc3xxx/Kconfig 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,31 @@ +config SND_LPC3XXX_SOC + tristate "SoC Audio for the NXP LPC32XX System-on-a-Chip" + depends on ARCH_LPC32XX && SND_SOC + help + Say Y or M if you want to add support for codecs attached to + the LPC3XXX I2S interface. You will also need to to select + the audio interfaces to support below. + +config SND_LPC3XXX_SOC_I2S + bool + +config SND_LPC32XX_USEI2S1 + bool "Use I2S1 channel instead of I2S0" + depends on SND_LPC3XXX_SOC && SND_LPC3XXX_SOC_I2S + help + The LPC32XX has 2 I2S channels (0 and 1). Normally, I2S0 is + used for communications with an I2S codec. If I2S1 should be + used instead, select this option. For LPC32XX systems that + used the LCD interface, I2S1 must be used. + +config SND_LPC3XXX_SOC_I2S_UDA1380 + tristate "SoC Audio support for Phytec 3250 board with the UDA1380" + depends on SND_LPC3XXX_SOC + select I2C + select SND_LPC3XXX_SOC_I2S + select SND_SOC_UDA1380 + help + Say Y or M here if you want to add support for SoC audio + on the Phytec 3250 board. This requires an I2C channel connected + to the I2C interface of the UDA1380 codec. + diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/sound/soc/lpc3xxx/lpc3xxx-i2s.c linux-2.6.27.8/sound/soc/lpc3xxx/lpc3xxx-i2s.c --- linux-2.6.27.8-base/sound/soc/lpc3xxx/lpc3xxx-i2s.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/sound/soc/lpc3xxx/lpc3xxx-i2s.c 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,510 @@ +/* + * sound/soc/lpc3xxx/lpc3xxx-i2s.c + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include "lpc3xxx-pcm.h" +#include "lpc3xxx-i2s.h" + +//#define I2S_DEBUG_INFO + +#define I2S_NAME "lpc3xxx-i2s" + +#define LPC3XXX_I2S_RATES \ + (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ + SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000) + +#define LPC3XXX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SND_SOC_DAIFMT_I2S | \ + SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_S32) + +static struct lpc3xxx_i2s_info i2s_info[NUM_I2S_DEVICES] = { + { + .name = "i2s0", + .lock = __SPIN_LOCK_UNLOCKED(i2s_info[0].lock), + .initialized = 0, + .clkname = "i2s0_ck", + .baseio = I2S0_BASE, + }, + { + .name = "i2s1", + .lock = __SPIN_LOCK_UNLOCKED(i2s_info[1].lock), + .initialized = 0, + .clkname = "i2s1_ck", + .baseio = I2S1_BASE, + }, +}; + +static u32 absd32(u32 v1, u32 v2) { + if (v1 > v2) { + return v1 - v2; + } + + return v2 - v1; +} + +static void __lpc3xxx_find_clkdiv(u32 *clkx, u32 *clky, int freq, + int xbytes, int channels, u32 clkrate) { + u32 i2srate; + u32 idxx, idyy; + u32 savedbitclkrate, diff, trate, baseclk; + + /* Adjust rate for sample size (bits) and channels and offset for + divider in clock output */ + i2srate = (freq / 100) * (u32) channels * (8 * xbytes); + i2srate = i2srate << 2; + clkrate = clkrate / 100; + baseclk = clkrate; + *clkx = 1; + *clky = 1; + + /* Find the best divider */ + *clkx = *clky = 0; + savedbitclkrate = 0; + diff = ~0; + for (idxx = 1; idxx < 0xFF; idxx++) { + for (idyy = 1; idyy < 0xFF; idyy++) { + trate = (baseclk * idxx) / idyy; + if (absd32(trate, i2srate) < diff) { + diff = absd32(trate, i2srate); + savedbitclkrate = trate; + *clkx = idxx; + *clky = idyy; + } + } + } +} + +static int lpc3xxx_i2s_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct lpc3xxx_i2s_info *i2s_info_p = &i2s_info[rtd->dai->cpu_dai->id]; + u32 dmamask; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + dmamask = I2S_DMA_XMIT; + } + else { + dmamask = I2S_DMA_RECV; + } + if (dmamask & i2s_info_p->dma_flags) { + /* This channel already enabled! */ + pr_warning("%s: I2S DMA channel is busy!\n", + I2S_NAME); + return -EBUSY; + } + + /* Initialize I2S interface */ + if (i2s_info_p->initialized == 0) { + i2s_info_p->clk = clk_get(NULL, i2s_info_p->clkname); + if (IS_ERR(i2s_info_p->clk)) { + i2s_info_p->clk = NULL; + pr_warning("%s: Failed enabling the I2S clock: %s\n", + I2S_NAME, i2s_info_p->clkname); + return -ENODEV; + } + + clk_enable(i2s_info_p->clk); + i2s_info_p->clkrate = clk_get_rate(i2s_info_p->clk); + if (i2s_info_p->clkrate == 0) { + pr_warning("%s: Invalid returned clock rate\n", + I2S_NAME); + clk_disable(i2s_info_p->clk); + clk_put(i2s_info_p->clk); + i2s_info_p->clk = NULL; + return -ENODEV; + } + + i2s_info_p->iomem = ioremap(i2s_info_p->baseio, SZ_4K); + if (i2s_info_p->iomem == NULL) { + pr_warning("%s: Can't remap I2S registers\n", + I2S_NAME); + clk_disable(i2s_info_p->clk); + clk_put(i2s_info_p->clk); + i2s_info_p->clk = NULL; + return -ENOMEM; + } + + /* I2S is setup here with a dummy configuration to allow the + bit clock to toggle. The CODEC attached to the I2S may not + work without this clock. The actual values here do not yet + matter abd will be reconfigured when needed by the I2S hw + setup function. */ + __raw_writel(I2S_DMA0_TX_DEPTH(4), + I2S_DMA1(i2s_info_p->iomem)); + __raw_writel(0x0110, I2S_TX_RATE(i2s_info_p->iomem)); + __raw_writel(0x83C1, I2S_DAO(i2s_info_p->iomem)); + + i2s_info_p->initialized = 1; + } + + i2s_info_p->dma_flags |= dmamask; + + return 0; +} + +static void lpc3xxx_i2s_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct lpc3xxx_i2s_info *i2s_info_p = &i2s_info[rtd->dai->cpu_dai->id]; + u32 dmamask, tmp; + + if (i2s_info_p->initialized == 0) { + /* Nothing is enabled! */ + pr_warning("%s: Shutdown when nothing is enabled!\n", + I2S_NAME); + return; + } + + /* Disable I2S based on stream */ + spin_lock_irq(&i2s_info_p->lock); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + dmamask = I2S_DMA_XMIT; + tmp = __raw_readl(I2S_DAO(i2s_info_p->iomem)); + tmp |= I2S_STOP; + __raw_writel(tmp, I2S_DAO(i2s_info_p->iomem)); + __raw_writel(0, I2S_TX_RATE(i2s_info_p->iomem)); + } + else { + dmamask = I2S_DMA_RECV; + tmp = __raw_readl(I2S_DAI(i2s_info_p->iomem)); + tmp |= I2S_STOP; + __raw_writel(tmp, I2S_DAI(i2s_info_p->iomem)); + __raw_writel(0, I2S_RX_RATE(i2s_info_p->iomem)); + } + + spin_unlock_irq(&i2s_info_p->lock); + + /* If both streams are shut down, then disable I2S to save power */ + i2s_info_p->dma_flags &= ~dmamask; + if (i2s_info_p->dma_flags == 0) { + clk_disable(i2s_info_p->clk); + clk_put(i2s_info_p->clk); + i2s_info_p->initialized = 0; + } +} + +static int lpc3xxx_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai, + int clk_id, unsigned int freq, int dir) +{ + struct lpc3xxx_i2s_info *i2s_info_p = &i2s_info[cpu_dai->id]; + + /* Will use in HW params later */ + i2s_info_p->freq = freq; + + return 0; +} + +static int lpc3xxx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, + unsigned int fmt) +{ + struct lpc3xxx_i2s_info *i2s_info_p = &i2s_info[cpu_dai->id]; + + /* Will use in HW params later */ + i2s_info_p->daifmt = fmt; + + return 0; +} + +static int lpc3xxx_i2s_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, + int div_id, int div) +{ + struct lpc3xxx_i2s_info *i2s_info_p = &i2s_info[cpu_dai->id]; + + /* This function doesn't help, but save the value anyways. + HW params will determine the correct clock divider based + on the frequency */ + i2s_info_p->clkdiv = div; + + return 0; +} + +static int lpc3xxx_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int id = rtd->dai->cpu_dai->id; + struct lpc3xxx_i2s_info *i2s_info_p; + int xfersize, ret; + u32 tmp, clkx, clky; + + i2s_info_p = &i2s_info[id]; + + /* Build the I2S setup word */ + tmp = 0; + switch (i2s_info_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SNDRV_PCM_FMTBIT_S8: + tmp |= I2S_WW8 | I2S_WS_HP(I2S_WW8_HP); + xfersize = 1; + break; + + case SNDRV_PCM_FMTBIT_S16: + case SND_SOC_DAIFMT_I2S: + tmp |= I2S_WW16 | I2S_WS_HP(I2S_WW16_HP); + xfersize = 2; + break; + + case SNDRV_PCM_FMTBIT_S32: + tmp |= I2S_WW32 | I2S_WS_HP(I2S_WW32_HP); + xfersize = 4; + break; + + default: + pr_warning("%s: Unsupported audio data format\n", + I2S_NAME); + return -EINVAL; + } + + /* Mono or stereo? */ + if (params_channels(params) == 1) { + tmp |= I2S_MONO; + } + + /* Find the best clock dividers to generate the requested + frequency */ + __lpc3xxx_find_clkdiv(&clkx, &clky, i2s_info_p->freq, xfersize, + params_channels(params), i2s_info_p->clkrate); + +#if defined(I2S_DEBUG_INFO) + printk("Desired clock rate : %d\n", i2s_info_p->freq); + printk("Base clock rate : %d\n", i2s_info_p->clkrate); + printk("Transfer size (bytes) : %d\n", xfersize); + printk("Clock divider (x) : %d\n", clkx); + printk("Clock divider (y) : %d\n", clky); + printk("Channels : %d\n", params_channels(params)); + printk("Data format : %d\n", i2s_info_p->daifmt); +#endif + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* Enable DAO support, correct clock rate, and DMA */ + __raw_writel(I2S_DMA1_TX_EN | I2S_DMA0_TX_DEPTH(4), + I2S_DMA1(i2s_info_p->iomem)); + __raw_writel(((clkx << 8) | clky), + I2S_TX_RATE(i2s_info_p->iomem)); + __raw_writel(tmp, I2S_DAO(i2s_info_p->iomem)); + +#if defined(I2S_DEBUG_INFO) + printk("TX DMA0 : 0x%x\n", + __raw_readl(I2S_DMA0(i2s_info_p->iomem))); + printk("TX dividers : 0x%x\n", + __raw_readl(I2S_TX_RATE(i2s_info_p->iomem))); + printk("TX DAO : 0x%x\n", + __raw_readl(I2S_DAO(i2s_info_p->iomem))); +#endif + } + else { + /* Enable DAI support, correct clock rate, and DMA */ + __raw_writel(I2S_DMA0_RX_EN | I2S_DMA1_RX_DEPTH(4), + I2S_DMA0(i2s_info_p->iomem)); + __raw_writel(((clkx << 8) | clky), + I2S_RX_RATE(i2s_info_p->iomem)); + __raw_writel(tmp, I2S_DAI(i2s_info_p->iomem)); + +#if defined(I2S_DEBUG_INFO) + printk("RX DMA1 : 0x%x\n", + __raw_readl(I2S_DMA1(i2s_info_p->iomem))); + printk("RX dividers : 0x%x\n", + __raw_readl(I2S_RX_RATE(i2s_info_p->iomem))); + printk("RX DAI : 0x%x\n", + __raw_readl(I2S_DAI(i2s_info_p->iomem))); +#endif + } + + return 0; +} + +static int lpc3xxx_i2s_prepare(struct snd_pcm_substream *substream) +{ + /* Nothing to do here */ + return 0; +} + +// FIXME - does this really work? +static int lpc3xxx_i2s_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int id = rtd->dai->cpu_dai->id; + struct lpc3xxx_i2s_info *i2s_info_p; + u32 tmp; + int ret = 0; + + i2s_info_p = &i2s_info[id]; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + tmp = __raw_readl(I2S_DAO(i2s_info_p->iomem)); + tmp |= I2S_STOP; + __raw_writel(tmp, I2S_DAO(i2s_info_p->iomem)); + } + break; + + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + tmp = __raw_readl(I2S_DAO(i2s_info_p->iomem)); + tmp &= ~I2S_STOP; + __raw_writel(tmp, I2S_DAO(i2s_info_p->iomem)); + } + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + break; + + default: + ret = -EINVAL; + } + + return ret; +} + +#ifdef CONFIG_PM +static int lpc3xxx_i2s_suspend(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) +{ + struct lpc3xxx_i2s_info *i2s_info_p = &i2s_info[cpu_dai->id]; + + if (!cpu_dai->active) + return 0; + + /* Save DA0, DAI, and IRQ register states */ + i2s_info_p->dao_save = __raw_readl(I2S_DAO(i2s_info_p->iomem)); + i2s_info_p->dai_save = __raw_readl(I2S_DAI(i2s_info_p->iomem)); + i2s_info_p->irq_save = __raw_readl(I2S_IRQ(i2s_info_p->iomem)); + + /* Disable system clock */ + clk_disable(i2s_info_p->clk); + + return 0; +} + +static int lpc3xxx_i2s_resume(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) +{ + struct lpc3xxx_i2s_info *i2s_info_p = &i2s_info[cpu_dai->id]; + + if (!cpu_dai->active) + return 0; + + /* Restore system clock */ + clk_enable(i2s_info_p->clk); + + /* Restore saved DA0, DAI, and IRQ register states */ + __raw_writel(i2s_info_p->dao_save, I2S_DAO(i2s_info_p->iomem)); + __raw_writel(i2s_info_p->dai_save, I2S_DAI(i2s_info_p->iomem)); + __raw_writel(i2s_info_p->irq_save, I2S_IRQ(i2s_info_p->iomem)); + + return 0; +} + +#else +# define lpc3xxx_i2s_suspend NULL +# define lpc3xxx_i2s_resume NULL +#endif + +struct snd_soc_dai lpc3xxx_i2s_dai[NUM_I2S_DEVICES] = { + { + .name = "lpc3xxx-i2s0", + .id = 0, + .type = SND_SOC_DAI_PCM, + .suspend = lpc3xxx_i2s_suspend, + .resume = lpc3xxx_i2s_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = LPC3XXX_I2S_RATES, + .formats = LPC3XXX_I2S_FORMATS, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = LPC3XXX_I2S_RATES, + .formats = LPC3XXX_I2S_FORMATS, + }, + .ops = { + .startup = lpc3xxx_i2s_startup, + .shutdown = lpc3xxx_i2s_shutdown, + .prepare = lpc3xxx_i2s_prepare, + .trigger = lpc3xxx_i2s_trigger, + .hw_params = lpc3xxx_i2s_hw_params, + }, + .dai_ops = { + .set_sysclk = lpc3xxx_i2s_set_dai_sysclk, + .set_fmt = lpc3xxx_i2s_set_dai_fmt, + .set_clkdiv = lpc3xxx_i2s_set_dai_clkdiv, + }, + .private_data = &i2s_info[0], + }, + { + .name = "lpc3xxx-i2s1", + .id = 1, + .type = SND_SOC_DAI_PCM, + .suspend = lpc3xxx_i2s_suspend, + .resume = lpc3xxx_i2s_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = LPC3XXX_I2S_RATES, + .formats = LPC3XXX_I2S_FORMATS, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = LPC3XXX_I2S_RATES, + .formats = LPC3XXX_I2S_FORMATS, + }, + .ops = { + .startup = lpc3xxx_i2s_startup, + .shutdown = lpc3xxx_i2s_shutdown, + .prepare = lpc3xxx_i2s_prepare, + .trigger = lpc3xxx_i2s_trigger, + .hw_params = lpc3xxx_i2s_hw_params, + }, + .dai_ops = { + .set_sysclk = lpc3xxx_i2s_set_dai_sysclk, + .set_fmt = lpc3xxx_i2s_set_dai_fmt, + .set_clkdiv = lpc3xxx_i2s_set_dai_clkdiv, + }, + .private_data = &i2s_info[1], + }, +}; +EXPORT_SYMBOL_GPL(lpc3xxx_i2s_dai); + + +MODULE_AUTHOR("Kevin Wells "); +MODULE_DESCRIPTION("ASoC LPC3XXX I2S interface"); +MODULE_LICENSE("GPL"); diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/sound/soc/lpc3xxx/lpc3xxx-i2s.h linux-2.6.27.8/sound/soc/lpc3xxx/lpc3xxx-i2s.h --- linux-2.6.27.8-base/sound/soc/lpc3xxx/lpc3xxx-i2s.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/sound/soc/lpc3xxx/lpc3xxx-i2s.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,53 @@ +/* + * sound/soc/lpc3xxx/lpc3xxx-i2s.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 __SOUND_SOC_LPC3XXX_I2S_H +#define __SOUND_SOC_LPC3XXX_I2S_H + +#include +#include +#include + +#define NUM_I2S_DEVICES 2 + +#define I2S_DMA_XMIT 0x1 +#define I2S_DMA_RECV 0x2 + +struct lpc3xxx_i2s_info { + char *name; + spinlock_t lock; + void *iomem; + unsigned short initialized; + u32 dma_flags; + char *clkname; + struct clk *clk; + u32 clkrate; + u32 baseio; + int freq; + unsigned short daifmt; + int clkdiv; + u32 dao_save, dai_save, irq_save; +}; + +extern struct snd_soc_dai lpc3xxx_i2s_dai[]; + +#endif diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/sound/soc/lpc3xxx/lpc3xxx-pcm.c linux-2.6.27.8/sound/soc/lpc3xxx/lpc3xxx-pcm.c --- linux-2.6.27.8-base/sound/soc/lpc3xxx/lpc3xxx-pcm.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/sound/soc/lpc3xxx/lpc3xxx-pcm.c 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,501 @@ +/* + * sound/soc/lpc3xxx/lpc3xxx-pcm.c + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include "lpc3xxx-pcm.h" + +#define SND_NAME "lpc3xxx-audio" +static u64 lpc3xxx_pcm_dmamask = 0xffffffff; + +#define NUMLINKS (32) +#define BUFFSIZE (NUMLINKS * 2048) + +static const struct snd_pcm_hardware lpc3xxx_pcm_hardware = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER), + .formats = (SND_SOC_DAIFMT_I2S), + .period_bytes_min = 128, + .period_bytes_max = 2048, + .periods_min = 2, + .periods_max = 1024, + .buffer_bytes_max = BUFFSIZE +}; + +struct lpc3xxx_dma_data { + dma_addr_t dma_buffer; /* physical address of DMA buffer */ + dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */ + size_t period_size; + + /* DMA configuration and support */ + int dmach; + struct dma_config dmacfg; + dma_addr_t period_ptr; /* physical address of next period */ + dma_addr_t dma_cur; + u32 llptr; /* Saved, not used */ +}; + +static int lpc3xxx_pcm_allocate_dma_buffer(struct snd_pcm *pcm, int stream) +{ + struct snd_pcm_substream *substream = pcm->streams[stream].substream; + struct snd_dma_buffer *dmabuf = &substream->dma_buffer; + size_t size = lpc3xxx_pcm_hardware.buffer_bytes_max; + + dmabuf->dev.type = SNDRV_DMA_TYPE_DEV; + dmabuf->dev.dev = pcm->card->dev; + dmabuf->private_data = NULL; + dmabuf->area = dma_alloc_writecombine(pcm->card->dev, size, + &dmabuf->addr, GFP_KERNEL); + + if (!dmabuf->area) + return -ENOMEM; + + dmabuf->bytes = size; + return 0; +} + +/* + * DMA ISR - occurs when a new DMA buffer is needed + */ +static void lpc3xxx_pcm_dma_irq(int channel, int cause, + struct snd_pcm_substream *substream) { + struct snd_pcm_runtime *rtd = substream->runtime; + struct lpc3xxx_dma_data *prtd = rtd->private_data; + int tq = 0; + static int count; + + count++; + + /* A DMA interrupt occurred - for most cases, this will be the end + of a transmitted buffer in the DMA link list, but errors are also + handled. */ + if (cause & DMA_ERR_INT) { + /* DMA error - this should never happen, but you just never + know. If it does happen, the driver will continue without + any problems except for maybe an audio glitch or pop. */ + printk("%s: DMA error %s (count=%d)\n", SND_NAME, + substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + "underrun" : "overrun", count); + } + + /* Dequeue buffers as needed */ + while (lpc32xx_get_free_llist_entry(channel) != 0) { + tq++; + prtd->dma_cur += prtd->period_size; + if (prtd->dma_cur >= prtd->dma_buffer_end) + prtd->dma_cur = prtd->dma_buffer; + } + + /* Re-queue buffers that were dequeued */ + while (tq > 0) { + tq--; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + lpc32xx_dma_queue_llist_entry(prtd->dmach, +#if defined(CONFIG_SND_LPC32XX_USEI2S1) + (void *) prtd->period_ptr, (void *) I2S_TX_FIFO(I2S1_BASE), +#else + (void *) prtd->period_ptr, (void *) I2S_TX_FIFO(I2S0_BASE), +#endif + prtd->period_size); + } + else { + lpc32xx_dma_queue_llist_entry(prtd->dmach, +#if defined(CONFIG_SND_LPC32XX_USEI2S1) + (void *) I2S_TX_FIFO(I2S1_BASE), (void *) prtd->period_ptr, +#else + (void *) I2S_TX_FIFO(I2S0_BASE), (void *) prtd->period_ptr, +#endif + prtd->period_size); + } + prtd->period_ptr += prtd->period_size; + if (prtd->period_ptr >= prtd->dma_buffer_end) + prtd->period_ptr = prtd->dma_buffer; + } + + snd_pcm_period_elapsed(substream); +} + +/* + * PCM operations + */ +static int lpc3xxx_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct lpc3xxx_dma_data *prtd = runtime->private_data; + + /* this may get called several times by oss emulation + * with different params + */ + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + runtime->dma_bytes = params_buffer_bytes(params); + + prtd->dma_buffer = runtime->dma_addr; + prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes; + prtd->period_size = params_period_bytes(params); + + return 0; +} + +static int lpc3xxx_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct lpc3xxx_dma_data *prtd = substream->runtime->private_data; + + /* Return the DMA channel */ + if (prtd->dmach != -1) { + lpc32xx_dma_ch_disable(prtd->dmach); + lpc32xx_dma_dealloc_llist(prtd->dmach); + lpc32xx_dma_ch_put(prtd->dmach); + prtd->dmach = -1; + } + + return 0; +} + +static int lpc3xxx_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct lpc3xxx_dma_data *prtd = substream->runtime->private_data; + + /* Setup DMA channel */ + if (prtd->dmach == -1) { + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + prtd->dmach = DMA_CH_I2S_TX; + prtd->dmacfg.ch = DMA_CH_I2S_TX; + prtd->dmacfg.tc_inten = 1; + prtd->dmacfg.err_inten = 1; + prtd->dmacfg.src_size = 2; + prtd->dmacfg.src_inc = 1; + prtd->dmacfg.src_ahb1 = 0; + prtd->dmacfg.src_bsize = DMAC_CHAN_SRC_BURST_4; + prtd->dmacfg.src_prph = 0; + prtd->dmacfg.dst_size = 2; + prtd->dmacfg.dst_inc = 0; + prtd->dmacfg.dst_bsize = DMAC_CHAN_DEST_BURST_4; + prtd->dmacfg.dst_ahb1 = 1; +#if defined(CONFIG_SND_LPC32XX_USEI2S1) + prtd->dmacfg.dst_prph = DMAC_DEST_PERIP(DMA_PERID_I2S1_DMA1); +#else + prtd->dmacfg.dst_prph = DMAC_DEST_PERIP(DMA_PERID_I2S0_DMA1); +#endif + prtd->dmacfg.flowctrl = DMAC_CHAN_FLOW_D_M2P; + if (lpc32xx_dma_ch_get(&prtd->dmacfg, "dma_i2s_tx", + &lpc3xxx_pcm_dma_irq, substream) < 0) { + printk(KERN_ERR "Error setting up I2S TX DMA channel\n"); + return -ENODEV; + } + + /* Allocate a linked list for audio buffers */ + prtd->llptr = lpc32xx_dma_alloc_llist(prtd->dmach, NUMLINKS); + if (prtd->llptr == 0) { + lpc32xx_dma_ch_put(prtd->dmach); + prtd->dmach = -1; + printk(KERN_ERR "Error allocating list buffer (I2S TX)\n"); + return -ENOMEM; + } + } + else { + prtd->dmach = DMA_CH_I2S_RX; + prtd->dmacfg.ch = DMA_CH_I2S_RX; + prtd->dmacfg.tc_inten = 1; + prtd->dmacfg.err_inten = 1; + prtd->dmacfg.src_size = 2; + prtd->dmacfg.src_inc = 0; + prtd->dmacfg.src_ahb1 = 1; + prtd->dmacfg.src_bsize = DMAC_CHAN_SRC_BURST_4; +#if defined(CONFIG_SND_LPC32XX_USEI2S1) + prtd->dmacfg.src_prph = DMAC_SRC_PERIP(DMA_PERID_I2S1_DMA0); +#else + prtd->dmacfg.src_prph = DMAC_SRC_PERIP(DMA_PERID_I2S0_DMA0); +#endif + prtd->dmacfg.dst_size = 2; + prtd->dmacfg.dst_inc = 1; + prtd->dmacfg.dst_ahb1 = 0; + prtd->dmacfg.dst_bsize = DMAC_CHAN_DEST_BURST_4; + prtd->dmacfg.dst_prph = 0; + prtd->dmacfg.flowctrl = DMAC_CHAN_FLOW_D_P2M; + if (lpc32xx_dma_ch_get(&prtd->dmacfg, "dma_i2s_rx", + &lpc3xxx_pcm_dma_irq, substream) < 0) { + printk(KERN_ERR "Error setting up I2S RX DMA channel\n"); + return -ENODEV; + } + + /* Allocate a linked list for audio buffers */ + prtd->llptr = lpc32xx_dma_alloc_llist(prtd->dmach, NUMLINKS); + if (prtd->llptr == 0) { + lpc32xx_dma_ch_put(prtd->dmach); + prtd->dmach = -1; + printk(KERN_ERR "Error allocating list buffer (I2S RX)\n"); + return -ENOMEM; + } + } + } + + return 0; +} + +static int lpc3xxx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_pcm_runtime *rtd = substream->runtime; + struct lpc3xxx_dma_data *prtd = rtd->private_data; + int i, ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + prtd->period_ptr = prtd->dma_cur = prtd->dma_buffer; + + /* Queue a few buffers to start DMA */ + for (i = 0; i < NUMLINKS; i++) { + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + lpc32xx_dma_queue_llist_entry(prtd->dmach, +#if defined(CONFIG_SND_LPC32XX_USEI2S1) + (void *) prtd->period_ptr, (void *) I2S_TX_FIFO(I2S1_BASE), +#else + (void *) prtd->period_ptr, (void *) I2S_TX_FIFO(I2S0_BASE), +#endif + prtd->period_size); + } + else { + lpc32xx_dma_queue_llist_entry(prtd->dmach, +#if defined(CONFIG_SND_LPC32XX_USEI2S1) + (void *) I2S_TX_FIFO(I2S1_BASE), (void *) prtd->period_ptr, +#else + (void *) I2S_TX_FIFO(I2S0_BASE), (void *) prtd->period_ptr, +#endif + prtd->period_size); + + } + + prtd->period_ptr += prtd->period_size; + } + break; + + case SNDRV_PCM_TRIGGER_STOP: + lpc32xx_dma_flush_llist(prtd->dmach); + lpc32xx_dma_ch_disable(prtd->dmach); + break; + + case SNDRV_PCM_TRIGGER_SUSPEND: + break; + + case SNDRV_PCM_TRIGGER_RESUME: + break; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + default: + ret = -EINVAL; + } + + return ret; +} + +static snd_pcm_uframes_t lpc3xxx_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct lpc3xxx_dma_data *prtd = runtime->private_data; + snd_pcm_uframes_t x; + + /* Return an offset into the DMA buffer for the next data */ + x = bytes_to_frames(runtime, (prtd->dma_cur - runtime->dma_addr)); + if (x >= runtime->buffer_size) + x = 0; + + return x; +} + +static int lpc3xxx_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct lpc3xxx_dma_data *prtd; + int ret = 0; + + snd_soc_set_runtime_hwparams(substream, &lpc3xxx_pcm_hardware); + + /* ensure that buffer size is a multiple of period size */ + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + goto out; + + prtd = kzalloc(sizeof(*prtd), GFP_KERNEL); + if (prtd == NULL) { + ret = -ENOMEM; + goto out; + } + runtime->private_data = prtd; + prtd->dmach = -1; + +out: + return ret; +} + +static int lpc3xxx_pcm_close(struct snd_pcm_substream *substream) +{ + struct lpc3xxx_dma_data *prtd = substream->runtime->private_data; + + kfree(prtd); + return 0; +} + +static int lpc3xxx_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + return dma_mmap_writecombine(substream->pcm->card->dev, vma, + runtime->dma_area, + runtime->dma_addr, + runtime->dma_bytes); +} + +static struct snd_pcm_ops lpc3xxx_pcm_ops = { + .open = lpc3xxx_pcm_open, + .close = lpc3xxx_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = lpc3xxx_pcm_hw_params, + .hw_free = lpc3xxx_pcm_hw_free, + .prepare = lpc3xxx_pcm_prepare, + .trigger = lpc3xxx_pcm_trigger, + .pointer = lpc3xxx_pcm_pointer, + .mmap = lpc3xxx_pcm_mmap, +}; + +/* + * ASoC platform driver + */ +static int lpc3xxx_pcm_new(struct snd_card *card, + struct snd_soc_dai *dai, + struct snd_pcm *pcm) +{ + int ret = 0; + + if (!card->dev->dma_mask) + card->dev->dma_mask = &lpc3xxx_pcm_dmamask; + if (!card->dev->coherent_dma_mask) + card->dev->coherent_dma_mask = 0xffffffff; + + if (dai->playback.channels_min) { + ret = lpc3xxx_pcm_allocate_dma_buffer( + pcm, SNDRV_PCM_STREAM_PLAYBACK); + if (ret) + goto out; + } + + if (dai->capture.channels_min) { + pr_debug("%s: Allocating PCM capture DMA buffer\n", SND_NAME); + ret = lpc3xxx_pcm_allocate_dma_buffer( + pcm, SNDRV_PCM_STREAM_CAPTURE); + if (ret) + goto out; + } + +out: + return ret; +} + +static void lpc3xxx_pcm_free_dma_buffers(struct snd_pcm *pcm) +{ + struct snd_pcm_substream *substream; + struct snd_dma_buffer *buf; + int stream; + + for (stream = 0; stream < 2; stream++) { + substream = pcm->streams[stream].substream; + if (substream == NULL) + continue; + + buf = &substream->dma_buffer; + if (!buf->area) + continue; + dma_free_writecombine(pcm->card->dev, buf->bytes, + buf->area, buf->addr); + + buf->area = NULL; + } +} + +#if defined(CONFIG_PM) +static int lpc3xxx_pcm_suspend(struct platform_device *pdev, + struct snd_soc_dai *dai) +{ + struct snd_pcm_runtime *runtime = dai->runtime; + struct lpc3xxx_dma_data *prtd; + + if (runtime == NULL) + return 0; + + prtd = runtime->private_data; + + /* Enable the DMA channel */ + lpc32xx_dma_ch_enable(prtd->dmach); + + return 0; +} + +static int lpc3xxx_pcm_resume(struct platform_device *pdev, + struct snd_soc_dai *dai) +{ + struct snd_pcm_runtime *runtime = dai->runtime; + struct lpc3xxx_dma_data *prtd; + + if (runtime == NULL) + return 0; + + prtd = runtime->private_data; + + /* Disable the DMA channel */ + lpc32xx_dma_ch_disable(prtd->dmach); + + return 0; +} + +#else +#define lpc3xxx_pcm_suspend NULL +#define lpc3xxx_pcm_resume NULL +#endif + +struct snd_soc_platform lpc3xxx_soc_platform = { + .name = SND_NAME, + .pcm_ops = &lpc3xxx_pcm_ops, + .pcm_new = lpc3xxx_pcm_new, + .pcm_free = lpc3xxx_pcm_free_dma_buffers, + .suspend = lpc3xxx_pcm_suspend, + .resume = lpc3xxx_pcm_resume, +}; +EXPORT_SYMBOL_GPL(lpc3xxx_soc_platform); + +MODULE_AUTHOR("Kevin Wells "); +MODULE_DESCRIPTION("NXP LPC3XXX PCM module"); +MODULE_LICENSE("GPL"); diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/sound/soc/lpc3xxx/lpc3xxx-pcm.h linux-2.6.27.8/sound/soc/lpc3xxx/lpc3xxx-pcm.h --- linux-2.6.27.8-base/sound/soc/lpc3xxx/lpc3xxx-pcm.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/sound/soc/lpc3xxx/lpc3xxx-pcm.h 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,29 @@ +/* + * sound/soc/lpc3xxx/lpc3xxx-pcm.h + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * 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 __SOUND_SOC_LPC3XXX_PCM_H +#define __SOUND_SOC_LPC3XXX_PCM_H + +extern struct snd_soc_platform lpc3xxx_soc_platform; + +#endif + diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/sound/soc/lpc3xxx/lpc3xxx-uda1380.c linux-2.6.27.8/sound/soc/lpc3xxx/lpc3xxx-uda1380.c --- linux-2.6.27.8-base/sound/soc/lpc3xxx/lpc3xxx-uda1380.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/sound/soc/lpc3xxx/lpc3xxx-uda1380.c 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,209 @@ +/* + * sound/soc/lpc3xxx/lpc3xxx-uda1380.c + * + * Author: Kevin Wells + * + * Copyright (C) 2008 NXP Semiconductors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../codecs/uda1380.h" +#include "lpc3xxx-pcm.h" +#include "lpc3xxx-i2s.h" + +#define SND_MODNAME "lpc3xxx_uda1380" + +static int phy3250_uda1380_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + const unsigned int fmt = (SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_CBM_CFS); + int ret; + + + /* Set the CPU I2S rate clock (first) */ + ret = snd_soc_dai_set_sysclk(cpu_dai, 0, params_rate(params), + SND_SOC_CLOCK_OUT); + if (ret < 0) { + pr_warning("%s: " + "Failed to set I2S clock (%d)\n", + SND_MODNAME, ret); + return ret; + } + + /* Set CPU and CODEC DAI format */ + ret = snd_soc_dai_set_fmt(cpu_dai, fmt); + if (ret < 0) { + pr_warning("%s: " + "Failed to set CPU DAI format (%d)\n", + SND_MODNAME, ret); + return ret; + } + ret = snd_soc_dai_set_fmt(codec_dai, fmt); + if (ret < 0) { + pr_warning("%s: " + "Failed to set CODEC DAI format (%d)\n", + SND_MODNAME, ret); + return ret; + } + + return 0; +} + +static struct snd_soc_ops phy3250_uda1380_ops = { + .hw_params = phy3250_uda1380_hw_params, +}; + +static const struct snd_soc_dapm_widget phy3250_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_LINE("Line In", NULL), +}; + +static const struct snd_soc_dapm_route intercon[] = { + /* Headphone connected to VOUTRHP, VOUTLHP */ + {"Headphone Jack", NULL, "VOUTRHP"}, + {"Headphone Jack", NULL, "VOUTLHP"}, + + /* Line Out connected to VOUTR, VOUTL */ + {"Line Out", NULL, "VOUTR"}, + {"Line Out", NULL, "VOUTL"}, + + /* Mic connected to VINM */ + {"Mic Jack", NULL, "VINM"}, + + /* Line In connected to VINR, VINL */ + {"Line In", NULL, "VINL"}, + {"Line In", NULL, "VINR"}, +}; + +static int phy3250_uda1380_init(struct snd_soc_codec *codec) +{ + /* Add widgets */ + snd_soc_dapm_new_controls(codec, phy3250_dapm_widgets, + ARRAY_SIZE(phy3250_dapm_widgets)); + + /* Set up davinci-evm specific audio path audio_map */ + snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); + + /* Always connected pins */ + snd_soc_dapm_enable_pin(codec, "Headphone Jack"); + snd_soc_dapm_enable_pin(codec, "Line Out"); + snd_soc_dapm_enable_pin(codec, "Mic Jack"); + snd_soc_dapm_enable_pin(codec, "Line In"); + + snd_soc_dapm_sync(codec); + + return 0; +} + +static struct snd_soc_dai_link phy3250_uda1380_dai = { + .name = "UDA1380", + .stream_name = "UDA1380 PCM", +#if defined(CONFIG_SND_LPC32XX_USEI2S1) + .cpu_dai = &lpc3xxx_i2s_dai[1], +#else + .cpu_dai = &lpc3xxx_i2s_dai[0], +#endif + .codec_dai = &uda1380_dai[0], + .init = phy3250_uda1380_init, + .ops = &phy3250_uda1380_ops, +}; + +static struct snd_soc_machine snd_soc_machine_phy3250 = { + .name = "LPC3XXX_I2S_UDA1380", + .dai_link = &phy3250_uda1380_dai, + .num_links = 1, +}; + +static struct uda1380_setup_data phy3250_uda1380_setup = { + .i2c_address = 0x18, + .dac_clk = UDA1380_DAC_CLK_WSPLL, +}; + +static struct snd_soc_device phy3250_uda1380_snd_devdata = { + .machine = &snd_soc_machine_phy3250, + .platform = &lpc3xxx_soc_platform, + .codec_dev = &soc_codec_dev_uda1380, + .codec_data = &phy3250_uda1380_setup, +}; + +static struct platform_device *phy3250_snd_device; +static int __init phy3250_asoc_init(void) +{ + int ret = 0; + + /* + * Create and register platform device + */ + phy3250_snd_device = platform_device_alloc("soc-audio", 0); + if (phy3250_snd_device == NULL) { + return -ENOMEM; + } + + platform_set_drvdata(phy3250_snd_device, &phy3250_uda1380_snd_devdata); + phy3250_uda1380_snd_devdata.dev = &phy3250_snd_device->dev; + + ret = platform_device_add(phy3250_snd_device); + if (ret) { + pr_warning("%s: platform_device_add failed (%d)\n", + SND_MODNAME, ret); + goto err_device_add; + } + + return 0; + +err_device_add: + if (phy3250_snd_device != NULL) { + platform_device_put(phy3250_snd_device); + phy3250_snd_device = NULL; + } + + return ret; +} + +static void __exit phy3250_asoc_exit(void) +{ + platform_device_unregister(phy3250_snd_device); + phy3250_snd_device = NULL; +} + +module_init(phy3250_asoc_init); +module_exit(phy3250_asoc_exit); + +MODULE_AUTHOR("Kevin Wells "); +MODULE_DESCRIPTION("ASoC machine driver for LPC3XXX/UDA1380"); +MODULE_LICENSE("GPL"); diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/sound/soc/lpc3xxx/Makefile linux-2.6.27.8/sound/soc/lpc3xxx/Makefile --- linux-2.6.27.8-base/sound/soc/lpc3xxx/Makefile 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.27.8/sound/soc/lpc3xxx/Makefile 2009-01-08 12:02:03.000000000 -0800 @@ -0,0 +1,11 @@ +# LPC3XXX Platform Support +snd-soc-lpc3xxx-objs := lpc3xxx-pcm.o +snd-soc-lpc3xxx-i2s-objs := lpc3xxx-i2s.o + +obj-$(CONFIG_SND_LPC3XXX_SOC) += snd-soc-lpc3xxx.o +obj-$(CONFIG_SND_LPC3XXX_SOC_I2S) += snd-soc-lpc3xxx-i2s.o + +# LPC3XXX Machine Support +snd-soc-lpc3xxx-uda1380-objs := lpc3xxx-uda1380.o + +obj-$(CONFIG_SND_LPC3XXX_SOC_I2S_UDA1380) += snd-soc-lpc3xxx-uda1380.o diff -Naur -X linux-2.6.27.8/Documentation/dontdiff linux-2.6.27.8-base/sound/soc/Makefile linux-2.6.27.8/sound/soc/Makefile --- linux-2.6.27.8-base/sound/soc/Makefile 2009-01-08 11:42:38.000000000 -0800 +++ linux-2.6.27.8/sound/soc/Makefile 2009-01-08 12:02:03.000000000 -0800 @@ -1,5 +1,5 @@ snd-soc-core-objs := soc-core.o soc-dapm.o obj-$(CONFIG_SND_SOC) += snd-soc-core.o -obj-$(CONFIG_SND_SOC) += codecs/ at32/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/ +obj-$(CONFIG_SND_SOC) += codecs/ at32/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/ lpc3xxx/ obj-$(CONFIG_SND_SOC) += omap/ au1x/