linux/arch/arm/mach-lpc32xx/phy3250.c
<<
>>
Prefs
   1/*
   2 * arch/arm/mach-lpc32xx/phy3250.c
   3 *
   4 * Author: Kevin Wells <kevin.wells@nxp.com>
   5 *
   6 * Copyright (C) 2010 NXP Semiconductors
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation; either version 2 of the License, or
  11 * (at your option) any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 */
  18
  19#include <linux/init.h>
  20#include <linux/platform_device.h>
  21#include <linux/sysdev.h>
  22#include <linux/interrupt.h>
  23#include <linux/irq.h>
  24#include <linux/dma-mapping.h>
  25#include <linux/device.h>
  26#include <linux/spi/spi.h>
  27#include <linux/spi/eeprom.h>
  28#include <linux/leds.h>
  29#include <linux/gpio.h>
  30#include <linux/amba/bus.h>
  31#include <linux/amba/clcd.h>
  32#include <linux/amba/pl022.h>
  33
  34#include <asm/setup.h>
  35#include <asm/mach-types.h>
  36#include <asm/mach/arch.h>
  37
  38#include <mach/hardware.h>
  39#include <mach/platform.h>
  40#include "common.h"
  41
  42/*
  43 * Mapped GPIOLIB GPIOs
  44 */
  45#define SPI0_CS_GPIO    LPC32XX_GPIO(LPC32XX_GPIO_P3_GRP, 5)
  46#define LCD_POWER_GPIO  LPC32XX_GPIO(LPC32XX_GPO_P3_GRP, 0)
  47#define BKL_POWER_GPIO  LPC32XX_GPIO(LPC32XX_GPO_P3_GRP, 4)
  48#define LED_GPIO        LPC32XX_GPIO(LPC32XX_GPO_P3_GRP, 1)
  49
  50/*
  51 * AMBA LCD controller
  52 */
  53static struct clcd_panel conn_lcd_panel = {
  54        .mode           = {
  55                .name           = "QVGA portrait",
  56                .refresh        = 60,
  57                .xres           = 240,
  58                .yres           = 320,
  59                .pixclock       = 191828,
  60                .left_margin    = 22,
  61                .right_margin   = 11,
  62                .upper_margin   = 2,
  63                .lower_margin   = 1,
  64                .hsync_len      = 5,
  65                .vsync_len      = 2,
  66                .sync           = 0,
  67                .vmode          = FB_VMODE_NONINTERLACED,
  68        },
  69        .width          = -1,
  70        .height         = -1,
  71        .tim2           = (TIM2_IVS | TIM2_IHS),
  72        .cntl           = (CNTL_BGR | CNTL_LCDTFT | CNTL_LCDVCOMP(1) |
  73                                CNTL_LCDBPP16_565),
  74        .bpp            = 16,
  75};
  76#define PANEL_SIZE (3 * SZ_64K)
  77
  78static int lpc32xx_clcd_setup(struct clcd_fb *fb)
  79{
  80        dma_addr_t dma;
  81
  82        fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev,
  83                PANEL_SIZE, &dma, GFP_KERNEL);
  84        if (!fb->fb.screen_base) {
  85                printk(KERN_ERR "CLCD: unable to map framebuffer\n");
  86                return -ENOMEM;
  87        }
  88
  89        fb->fb.fix.smem_start = dma;
  90        fb->fb.fix.smem_len = PANEL_SIZE;
  91        fb->panel = &conn_lcd_panel;
  92
  93        if (gpio_request(LCD_POWER_GPIO, "LCD power"))
  94                printk(KERN_ERR "Error requesting gpio %u",
  95                        LCD_POWER_GPIO);
  96        else if (gpio_direction_output(LCD_POWER_GPIO, 1))
  97                printk(KERN_ERR "Error setting gpio %u to output",
  98                        LCD_POWER_GPIO);
  99
 100        if (gpio_request(BKL_POWER_GPIO, "LCD backlight power"))
 101                printk(KERN_ERR "Error requesting gpio %u",
 102                        BKL_POWER_GPIO);
 103        else if (gpio_direction_output(BKL_POWER_GPIO, 1))
 104                printk(KERN_ERR "Error setting gpio %u to output",
 105                        BKL_POWER_GPIO);
 106
 107        return 0;
 108}
 109
 110static int lpc32xx_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
 111{
 112        return dma_mmap_writecombine(&fb->dev->dev, vma,
 113                fb->fb.screen_base, fb->fb.fix.smem_start,
 114                fb->fb.fix.smem_len);
 115}
 116
 117static void lpc32xx_clcd_remove(struct clcd_fb *fb)
 118{
 119        dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
 120                fb->fb.screen_base, fb->fb.fix.smem_start);
 121}
 122
 123/*
 124 * On some early LCD modules (1307.0), the backlight logic is inverted.
 125 * For those board variants, swap the disable and enable states for
 126 * BKL_POWER_GPIO.
 127*/
 128static void clcd_disable(struct clcd_fb *fb)
 129{
 130        gpio_set_value(BKL_POWER_GPIO, 0);
 131        gpio_set_value(LCD_POWER_GPIO, 0);
 132}
 133
 134static void clcd_enable(struct clcd_fb *fb)
 135{
 136        gpio_set_value(BKL_POWER_GPIO, 1);
 137        gpio_set_value(LCD_POWER_GPIO, 1);
 138}
 139
 140static struct clcd_board lpc32xx_clcd_data = {
 141        .name           = "Phytec LCD",
 142        .check          = clcdfb_check,
 143        .decode         = clcdfb_decode,
 144        .disable        = clcd_disable,
 145        .enable         = clcd_enable,
 146        .setup          = lpc32xx_clcd_setup,
 147        .mmap           = lpc32xx_clcd_mmap,
 148        .remove         = lpc32xx_clcd_remove,
 149};
 150
 151static struct amba_device lpc32xx_clcd_device = {
 152        .dev                            = {
 153                .coherent_dma_mask      = ~0,
 154                .init_name              = "dev:clcd",
 155                .platform_data          = &lpc32xx_clcd_data,
 156        },
 157        .res                            = {
 158                .start                  = LPC32XX_LCD_BASE,
 159                .end                    = (LPC32XX_LCD_BASE + SZ_4K - 1),
 160                .flags                  = IORESOURCE_MEM,
 161        },
 162        .dma_mask                       = ~0,
 163        .irq                            = {IRQ_LPC32XX_LCD, NO_IRQ},
 164};
 165
 166/*
 167 * AMBA SSP (SPI)
 168 */
 169static void phy3250_spi_cs_set(u32 control)
 170{
 171        gpio_set_value(SPI0_CS_GPIO, (int) control);
 172}
 173
 174static struct pl022_config_chip spi0_chip_info = {
 175        .com_mode               = INTERRUPT_TRANSFER,
 176        .iface                  = SSP_INTERFACE_MOTOROLA_SPI,
 177        .hierarchy              = SSP_MASTER,
 178        .slave_tx_disable       = 0,
 179        .rx_lev_trig            = SSP_RX_4_OR_MORE_ELEM,
 180        .tx_lev_trig            = SSP_TX_4_OR_MORE_EMPTY_LOC,
 181        .ctrl_len               = SSP_BITS_8,
 182        .wait_state             = SSP_MWIRE_WAIT_ZERO,
 183        .duplex                 = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX,
 184        .cs_control             = phy3250_spi_cs_set,
 185};
 186
 187static struct pl022_ssp_controller lpc32xx_ssp0_data = {
 188        .bus_id                 = 0,
 189        .num_chipselect         = 1,
 190        .enable_dma             = 0,
 191};
 192
 193static struct amba_device lpc32xx_ssp0_device = {
 194        .dev                            = {
 195                .coherent_dma_mask      = ~0,
 196                .init_name              = "dev:ssp0",
 197                .platform_data          = &lpc32xx_ssp0_data,
 198        },
 199        .res                            = {
 200                .start                  = LPC32XX_SSP0_BASE,
 201                .end                    = (LPC32XX_SSP0_BASE + SZ_4K - 1),
 202                .flags                  = IORESOURCE_MEM,
 203        },
 204        .dma_mask                       = ~0,
 205        .irq                            = {IRQ_LPC32XX_SSP0, NO_IRQ},
 206};
 207
 208/* AT25 driver registration */
 209static int __init phy3250_spi_board_register(void)
 210{
 211#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
 212        static struct spi_board_info info[] = {
 213                {
 214                        .modalias = "spidev",
 215                        .max_speed_hz = 5000000,
 216                        .bus_num = 0,
 217                        .chip_select = 0,
 218                        .controller_data = &spi0_chip_info,
 219                },
 220        };
 221
 222#else
 223        static struct spi_eeprom eeprom = {
 224                .name = "at25256a",
 225                .byte_len = 0x8000,
 226                .page_size = 64,
 227                .flags = EE_ADDR2,
 228        };
 229
 230        static struct spi_board_info info[] = {
 231                {
 232                        .modalias = "at25",
 233                        .max_speed_hz = 5000000,
 234                        .bus_num = 0,
 235                        .chip_select = 0,
 236                        .mode = SPI_MODE_0,
 237                        .platform_data = &eeprom,
 238                        .controller_data = &spi0_chip_info,
 239                },
 240        };
 241#endif
 242        return spi_register_board_info(info, ARRAY_SIZE(info));
 243}
 244arch_initcall(phy3250_spi_board_register);
 245
 246static struct i2c_board_info __initdata phy3250_i2c_board_info[] = {
 247        {
 248                I2C_BOARD_INFO("pcf8563", 0x51),
 249        },
 250};
 251
 252static struct gpio_led phy_leds[] = {
 253        {
 254                .name                   = "led0",
 255                .gpio                   = LED_GPIO,
 256                .active_low             = 1,
 257                .default_trigger        = "heartbeat",
 258        },
 259};
 260
 261static struct gpio_led_platform_data led_data = {
 262        .leds = phy_leds,
 263        .num_leds = ARRAY_SIZE(phy_leds),
 264};
 265
 266static struct platform_device lpc32xx_gpio_led_device = {
 267        .name                   = "leds-gpio",
 268        .id                     = -1,
 269        .dev.platform_data      = &led_data,
 270};
 271
 272static struct platform_device *phy3250_devs[] __initdata = {
 273        &lpc32xx_i2c0_device,
 274        &lpc32xx_i2c1_device,
 275        &lpc32xx_i2c2_device,
 276        &lpc32xx_watchdog_device,
 277        &lpc32xx_gpio_led_device,
 278};
 279
 280static struct amba_device *amba_devs[] __initdata = {
 281        &lpc32xx_clcd_device,
 282        &lpc32xx_ssp0_device,
 283};
 284
 285/*
 286 * Board specific functions
 287 */
 288static void __init phy3250_board_init(void)
 289{
 290        u32 tmp;
 291        int i;
 292
 293        lpc32xx_gpio_init();
 294
 295        /* Register GPIOs used on this board */
 296        if (gpio_request(SPI0_CS_GPIO, "spi0 cs"))
 297                printk(KERN_ERR "Error requesting gpio %u",
 298                        SPI0_CS_GPIO);
 299        else if (gpio_direction_output(SPI0_CS_GPIO, 1))
 300                printk(KERN_ERR "Error setting gpio %u to output",
 301                        SPI0_CS_GPIO);
 302
 303        /* Setup network interface for RMII mode */
 304        tmp = __raw_readl(LPC32XX_CLKPWR_MACCLK_CTRL);
 305        tmp &= ~LPC32XX_CLKPWR_MACCTRL_PINS_MSK;
 306        tmp |= LPC32XX_CLKPWR_MACCTRL_USE_RMII_PINS;
 307        __raw_writel(tmp, LPC32XX_CLKPWR_MACCLK_CTRL);
 308
 309        /* Setup SLC NAND controller muxing */
 310        __raw_writel(LPC32XX_CLKPWR_NANDCLK_SEL_SLC,
 311                LPC32XX_CLKPWR_NAND_CLK_CTRL);
 312
 313        /* Setup LCD muxing to RGB565 */
 314        tmp = __raw_readl(LPC32XX_CLKPWR_LCDCLK_CTRL) &
 315                ~(LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_MSK |
 316                LPC32XX_CLKPWR_LCDCTRL_PSCALE_MSK);
 317        tmp |= LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_TFT16;
 318        __raw_writel(tmp, LPC32XX_CLKPWR_LCDCLK_CTRL);
 319
 320        /* Set up I2C pull levels */
 321        tmp = __raw_readl(LPC32XX_CLKPWR_I2C_CLK_CTRL);
 322        tmp |= LPC32XX_CLKPWR_I2CCLK_USBI2CHI_DRIVE |
 323                LPC32XX_CLKPWR_I2CCLK_I2C2HI_DRIVE;
 324        __raw_writel(tmp, LPC32XX_CLKPWR_I2C_CLK_CTRL);
 325
 326        /* Disable IrDA pulsing support on UART6 */
 327        tmp = __raw_readl(LPC32XX_UARTCTL_CTRL);
 328        tmp |= LPC32XX_UART_UART6_IRDAMOD_BYPASS;
 329        __raw_writel(tmp, LPC32XX_UARTCTL_CTRL);
 330
 331        /* Enable DMA for I2S1 channel */
 332        tmp = __raw_readl(LPC32XX_CLKPWR_I2S_CLK_CTRL);
 333        tmp = LPC32XX_CLKPWR_I2SCTRL_I2S1_USE_DMA;
 334        __raw_writel(tmp, LPC32XX_CLKPWR_I2S_CLK_CTRL);
 335
 336        lpc32xx_serial_init();
 337
 338        /*
 339         * AMBA peripheral clocks need to be enabled prior to AMBA device
 340         * detection or a data fault will occur, so enable the clocks
 341         * here. However, we don't want to enable them if the peripheral
 342         * isn't included in the image
 343         */
 344#ifdef CONFIG_FB_ARMCLCD
 345        tmp = __raw_readl(LPC32XX_CLKPWR_LCDCLK_CTRL);
 346        __raw_writel((tmp | LPC32XX_CLKPWR_LCDCTRL_CLK_EN),
 347                LPC32XX_CLKPWR_LCDCLK_CTRL);
 348#endif
 349#ifdef CONFIG_SPI_PL022
 350        tmp = __raw_readl(LPC32XX_CLKPWR_SSP_CLK_CTRL);
 351        __raw_writel((tmp | LPC32XX_CLKPWR_SSPCTRL_SSPCLK0_EN),
 352                LPC32XX_CLKPWR_SSP_CLK_CTRL);
 353#endif
 354
 355        platform_add_devices(phy3250_devs, ARRAY_SIZE(phy3250_devs));
 356        for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
 357                struct amba_device *d = amba_devs[i];
 358                amba_device_register(d, &iomem_resource);
 359        }
 360
 361        /* Test clock needed for UDA1380 initial init */
 362        __raw_writel(LPC32XX_CLKPWR_TESTCLK2_SEL_MOSC |
 363                LPC32XX_CLKPWR_TESTCLK_TESTCLK2_EN,
 364                LPC32XX_CLKPWR_TEST_CLK_SEL);
 365
 366        i2c_register_board_info(0, phy3250_i2c_board_info,
 367                ARRAY_SIZE(phy3250_i2c_board_info));
 368}
 369
 370static int __init lpc32xx_display_uid(void)
 371{
 372        u32 uid[4];
 373
 374        lpc32xx_get_uid(uid);
 375
 376        printk(KERN_INFO "LPC32XX unique ID: %08x%08x%08x%08x\n",
 377                uid[3], uid[2], uid[1], uid[0]);
 378
 379        return 1;
 380}
 381arch_initcall(lpc32xx_display_uid);
 382
 383MACHINE_START(PHY3250, "Phytec 3250 board with the LPC3250 Microcontroller")
 384        /* Maintainer: Kevin Wells, NXP Semiconductors */
 385        .boot_params    = 0x80000100,
 386        .map_io         = lpc32xx_map_io,
 387        .init_irq       = lpc32xx_init_irq,
 388        .timer          = &lpc32xx_timer,
 389        .init_machine   = phy3250_board_init,
 390MACHINE_END
 391