cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mach-mini2440.c (20029B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// Copyright (c) 2008 Ramax Lo <ramaxlo@gmail.com>
      4//      Based on mach-anubis.c by Ben Dooks <ben@simtec.co.uk>
      5//      and modifications by SBZ <sbz@spgui.org> and
      6//      Weibing <http://weibing.blogbus.com> and
      7//      Michel Pollet <buserror@gmail.com>
      8//
      9// For product information, visit https://code.google.com/p/mini2440/
     10
     11#include <linux/kernel.h>
     12#include <linux/types.h>
     13#include <linux/interrupt.h>
     14#include <linux/list.h>
     15#include <linux/timer.h>
     16#include <linux/init.h>
     17#include <linux/gpio.h>
     18#include <linux/gpio/machine.h>
     19#include <linux/input.h>
     20#include <linux/io.h>
     21#include <linux/serial_core.h>
     22#include <linux/serial_s3c.h>
     23#include <linux/dm9000.h>
     24#include <linux/property.h>
     25#include <linux/platform_device.h>
     26#include <linux/gpio_keys.h>
     27#include <linux/i2c.h>
     28#include <linux/mmc/host.h>
     29
     30#include <asm/mach/arch.h>
     31#include <asm/mach/map.h>
     32
     33#include <linux/platform_data/fb-s3c2410.h>
     34#include <asm/mach-types.h>
     35
     36#include "regs-gpio.h"
     37#include <linux/platform_data/leds-s3c24xx.h>
     38#include "irqs.h"
     39#include "gpio-samsung.h"
     40#include <linux/platform_data/mtd-nand-s3c2410.h>
     41#include <linux/platform_data/i2c-s3c2410.h>
     42#include <linux/platform_data/mmc-s3cmci.h>
     43#include <linux/platform_data/usb-s3c2410_udc.h>
     44
     45#include <linux/mtd/mtd.h>
     46#include <linux/mtd/rawnand.h>
     47#include <linux/mtd/nand-ecc-sw-hamming.h>
     48#include <linux/mtd/partitions.h>
     49
     50#include "gpio-cfg.h"
     51#include "devs.h"
     52#include "cpu.h"
     53
     54#include <sound/s3c24xx_uda134x.h>
     55
     56#include "s3c24xx.h"
     57
     58#define MACH_MINI2440_DM9K_BASE (S3C2410_CS4 + 0x300)
     59
     60static struct map_desc mini2440_iodesc[] __initdata = {
     61	/* nothing to declare, move along */
     62};
     63
     64#define UCON S3C2410_UCON_DEFAULT
     65#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB)
     66#define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE)
     67
     68
     69static struct s3c2410_uartcfg mini2440_uartcfgs[] __initdata = {
     70	[0] = {
     71		.hwport		= 0,
     72		.flags		= 0,
     73		.ucon		= UCON,
     74		.ulcon		= ULCON,
     75		.ufcon		= UFCON,
     76	},
     77	[1] = {
     78		.hwport		= 1,
     79		.flags		= 0,
     80		.ucon		= UCON,
     81		.ulcon		= ULCON,
     82		.ufcon		= UFCON,
     83	},
     84	[2] = {
     85		.hwport		= 2,
     86		.flags		= 0,
     87		.ucon		= UCON,
     88		.ulcon		= ULCON,
     89		.ufcon		= UFCON,
     90	},
     91};
     92
     93/* USB device UDC support */
     94
     95static struct s3c2410_udc_mach_info mini2440_udc_cfg __initdata = {
     96	.pullup_pin = S3C2410_GPC(5),
     97};
     98
     99
    100/* LCD timing and setup */
    101
    102/*
    103 * This macro simplifies the table bellow
    104 */
    105#define _LCD_DECLARE(_clock, _xres, margin_left, margin_right, hsync, \
    106			_yres, margin_top, margin_bottom, vsync, refresh) \
    107	.width = _xres, \
    108	.xres = _xres, \
    109	.height = _yres, \
    110	.yres = _yres, \
    111	.left_margin	= margin_left,	\
    112	.right_margin	= margin_right,	\
    113	.upper_margin	= margin_top,	\
    114	.lower_margin	= margin_bottom,	\
    115	.hsync_len	= hsync,	\
    116	.vsync_len	= vsync,	\
    117	.pixclock	= ((_clock*100000000000LL) /	\
    118			   ((refresh) * \
    119			   (hsync + margin_left + _xres + margin_right) * \
    120			   (vsync + margin_top + _yres + margin_bottom))), \
    121	.bpp		= 16,\
    122	.type		= (S3C2410_LCDCON1_TFT16BPP |\
    123			   S3C2410_LCDCON1_TFT)
    124
    125static struct s3c2410fb_display mini2440_lcd_cfg[] __initdata = {
    126	[0] = {	/* mini2440 + 3.5" TFT + touchscreen */
    127		_LCD_DECLARE(
    128			7,			/* The 3.5 is quite fast */
    129			240, 21, 38, 6,		/* x timing */
    130			320, 4, 4, 2,		/* y timing */
    131			60),			/* refresh rate */
    132		.lcdcon5	= (S3C2410_LCDCON5_FRM565 |
    133				   S3C2410_LCDCON5_INVVLINE |
    134				   S3C2410_LCDCON5_INVVFRAME |
    135				   S3C2410_LCDCON5_INVVDEN |
    136				   S3C2410_LCDCON5_PWREN),
    137	},
    138	[1] = { /* mini2440 + 7" TFT + touchscreen */
    139		_LCD_DECLARE(
    140			10,			/* the 7" runs slower */
    141			800, 40, 40, 48,	/* x timing */
    142			480, 29, 3, 3,		/* y timing */
    143			50),			/* refresh rate */
    144		.lcdcon5	= (S3C2410_LCDCON5_FRM565 |
    145				   S3C2410_LCDCON5_INVVLINE |
    146				   S3C2410_LCDCON5_INVVFRAME |
    147				   S3C2410_LCDCON5_PWREN),
    148	},
    149	/* The VGA shield can outout at several resolutions. All share
    150	 * the same timings, however, anything smaller than 1024x768
    151	 * will only be displayed in the top left corner of a 1024x768
    152	 * XGA output unless you add optional dip switches to the shield.
    153	 * Therefore timings for other resolutions have been omitted here.
    154	 */
    155	[2] = {
    156		_LCD_DECLARE(
    157			10,
    158			1024, 1, 2, 2,		/* y timing */
    159			768, 200, 16, 16,	/* x timing */
    160			24),	/* refresh rate, maximum stable,
    161				 * tested with the FPGA shield
    162				 */
    163		.lcdcon5	= (S3C2410_LCDCON5_FRM565 |
    164				   S3C2410_LCDCON5_HWSWP),
    165	},
    166	/* mini2440 + 3.5" TFT (LCD-W35i, LQ035Q1DG06 type) + touchscreen*/
    167	[3] = {
    168		_LCD_DECLARE(
    169			/* clock */
    170			7,
    171			/* xres, margin_right, margin_left, hsync */
    172			320, 68, 66, 4,
    173			/* yres, margin_top, margin_bottom, vsync */
    174			240, 4, 4, 9,
    175			/* refresh rate */
    176			60),
    177		.lcdcon5	= (S3C2410_LCDCON5_FRM565 |
    178				   S3C2410_LCDCON5_INVVDEN |
    179				   S3C2410_LCDCON5_INVVFRAME |
    180				   S3C2410_LCDCON5_INVVLINE |
    181				   S3C2410_LCDCON5_INVVCLK |
    182				   S3C2410_LCDCON5_HWSWP),
    183	},
    184};
    185
    186/* todo - put into gpio header */
    187
    188#define S3C2410_GPCCON_MASK(x)	(3 << ((x) * 2))
    189#define S3C2410_GPDCON_MASK(x)	(3 << ((x) * 2))
    190
    191static struct s3c2410fb_mach_info mini2440_fb_info __initdata = {
    192	.displays	 = &mini2440_lcd_cfg[0], /* not constant! see init */
    193	.num_displays	 = 1,
    194	.default_display = 0,
    195
    196	/* Enable VD[2..7], VD[10..15], VD[18..23] and VCLK, syncs, VDEN
    197	 * and disable the pull down resistors on pins we are using for LCD
    198	 * data.
    199	 */
    200
    201	.gpcup		= (0xf << 1) | (0x3f << 10),
    202
    203	.gpccon		= (S3C2410_GPC1_VCLK   | S3C2410_GPC2_VLINE |
    204			   S3C2410_GPC3_VFRAME | S3C2410_GPC4_VM |
    205			   S3C2410_GPC10_VD2   | S3C2410_GPC11_VD3 |
    206			   S3C2410_GPC12_VD4   | S3C2410_GPC13_VD5 |
    207			   S3C2410_GPC14_VD6   | S3C2410_GPC15_VD7),
    208
    209	.gpccon_mask	= (S3C2410_GPCCON_MASK(1)  | S3C2410_GPCCON_MASK(2)  |
    210			   S3C2410_GPCCON_MASK(3)  | S3C2410_GPCCON_MASK(4)  |
    211			   S3C2410_GPCCON_MASK(10) | S3C2410_GPCCON_MASK(11) |
    212			   S3C2410_GPCCON_MASK(12) | S3C2410_GPCCON_MASK(13) |
    213			   S3C2410_GPCCON_MASK(14) | S3C2410_GPCCON_MASK(15)),
    214
    215	.gpccon_reg	= S3C2410_GPCCON,
    216	.gpcup_reg	= S3C2410_GPCUP,
    217
    218	.gpdup		= (0x3f << 2) | (0x3f << 10),
    219
    220	.gpdcon		= (S3C2410_GPD2_VD10  | S3C2410_GPD3_VD11 |
    221			   S3C2410_GPD4_VD12  | S3C2410_GPD5_VD13 |
    222			   S3C2410_GPD6_VD14  | S3C2410_GPD7_VD15 |
    223			   S3C2410_GPD10_VD18 | S3C2410_GPD11_VD19 |
    224			   S3C2410_GPD12_VD20 | S3C2410_GPD13_VD21 |
    225			   S3C2410_GPD14_VD22 | S3C2410_GPD15_VD23),
    226
    227	.gpdcon_mask	= (S3C2410_GPDCON_MASK(2)  | S3C2410_GPDCON_MASK(3) |
    228			   S3C2410_GPDCON_MASK(4)  | S3C2410_GPDCON_MASK(5) |
    229			   S3C2410_GPDCON_MASK(6)  | S3C2410_GPDCON_MASK(7) |
    230			   S3C2410_GPDCON_MASK(10) | S3C2410_GPDCON_MASK(11)|
    231			   S3C2410_GPDCON_MASK(12) | S3C2410_GPDCON_MASK(13)|
    232			   S3C2410_GPDCON_MASK(14) | S3C2410_GPDCON_MASK(15)),
    233
    234	.gpdcon_reg	= S3C2410_GPDCON,
    235	.gpdup_reg	= S3C2410_GPDUP,
    236};
    237
    238/* MMC/SD  */
    239
    240static struct s3c24xx_mci_pdata mini2440_mmc_cfg __initdata = {
    241	.wprotect_invert	= 1,
    242	.set_power		= s3c24xx_mci_def_set_power,
    243	.ocr_avail		= MMC_VDD_32_33|MMC_VDD_33_34,
    244};
    245
    246static struct gpiod_lookup_table mini2440_mmc_gpio_table = {
    247	.dev_id = "s3c2410-sdi",
    248	.table = {
    249		/* Card detect S3C2410_GPG(8) */
    250		GPIO_LOOKUP("GPIOG", 8, "cd", GPIO_ACTIVE_LOW),
    251		/* Write protect S3C2410_GPH(8) */
    252		GPIO_LOOKUP("GPIOH", 8, "wp", GPIO_ACTIVE_HIGH),
    253		/* bus pins */
    254		GPIO_LOOKUP_IDX("GPIOE",  5, "bus", 0, GPIO_ACTIVE_HIGH),
    255		GPIO_LOOKUP_IDX("GPIOE",  6, "bus", 1, GPIO_ACTIVE_HIGH),
    256		GPIO_LOOKUP_IDX("GPIOE",  7, "bus", 2, GPIO_ACTIVE_HIGH),
    257		GPIO_LOOKUP_IDX("GPIOE",  8, "bus", 3, GPIO_ACTIVE_HIGH),
    258		GPIO_LOOKUP_IDX("GPIOE",  9, "bus", 4, GPIO_ACTIVE_HIGH),
    259		GPIO_LOOKUP_IDX("GPIOE", 10, "bus", 5, GPIO_ACTIVE_HIGH),
    260		{ },
    261	},
    262};
    263
    264/* NAND Flash on MINI2440 board */
    265
    266static struct mtd_partition mini2440_default_nand_part[] __initdata = {
    267	[0] = {
    268		.name	= "u-boot",
    269		.size	= SZ_256K,
    270		.offset	= 0,
    271	},
    272	[1] = {
    273		.name	= "u-boot-env",
    274		.size	= SZ_128K,
    275		.offset	= SZ_256K,
    276	},
    277	[2] = {
    278		.name	= "kernel",
    279		/* 5 megabytes, for a kernel with no modules
    280		 * or a uImage with a ramdisk attached
    281		 */
    282		.size	= 0x00500000,
    283		.offset	= SZ_256K + SZ_128K,
    284	},
    285	[3] = {
    286		.name	= "root",
    287		.offset	= SZ_256K + SZ_128K + 0x00500000,
    288		.size	= MTDPART_SIZ_FULL,
    289	},
    290};
    291
    292static struct s3c2410_nand_set mini2440_nand_sets[] __initdata = {
    293	[0] = {
    294		.name		= "nand",
    295		.nr_chips	= 1,
    296		.nr_partitions	= ARRAY_SIZE(mini2440_default_nand_part),
    297		.partitions	= mini2440_default_nand_part,
    298		.flash_bbt	= 1, /* we use u-boot to create a BBT */
    299	},
    300};
    301
    302static struct s3c2410_platform_nand mini2440_nand_info __initdata = {
    303	.tacls		= 0,
    304	.twrph0		= 25,
    305	.twrph1		= 15,
    306	.nr_sets	= ARRAY_SIZE(mini2440_nand_sets),
    307	.sets		= mini2440_nand_sets,
    308	.ignore_unset_ecc = 1,
    309	.engine_type	= NAND_ECC_ENGINE_TYPE_ON_HOST,
    310};
    311
    312/* DM9000AEP 10/100 ethernet controller */
    313
    314static struct resource mini2440_dm9k_resource[] = {
    315	[0] = DEFINE_RES_MEM(MACH_MINI2440_DM9K_BASE, 4),
    316	[1] = DEFINE_RES_MEM(MACH_MINI2440_DM9K_BASE + 4, 4),
    317	[2] = DEFINE_RES_NAMED(IRQ_EINT7, 1, NULL, IORESOURCE_IRQ
    318						| IORESOURCE_IRQ_HIGHEDGE),
    319};
    320
    321/*
    322 * The DM9000 has no eeprom, and it's MAC address is set by
    323 * the bootloader before starting the kernel.
    324 */
    325static struct dm9000_plat_data mini2440_dm9k_pdata = {
    326	.flags		= (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM),
    327};
    328
    329static struct platform_device mini2440_device_eth = {
    330	.name		= "dm9000",
    331	.id		= -1,
    332	.num_resources	= ARRAY_SIZE(mini2440_dm9k_resource),
    333	.resource	= mini2440_dm9k_resource,
    334	.dev		= {
    335		.platform_data	= &mini2440_dm9k_pdata,
    336	},
    337};
    338
    339/*  CON5
    340 *	+--+	 /-----\
    341 *	|  |    |	|
    342 *	|  |	|  BAT	|
    343 *	|  |	 \_____/
    344 *	|  |
    345 *	|  |  +----+  +----+
    346 *	|  |  | K5 |  | K1 |
    347 *	|  |  +----+  +----+
    348 *	|  |  +----+  +----+
    349 *	|  |  | K4 |  | K2 |
    350 *	|  |  +----+  +----+
    351 *	|  |  +----+  +----+
    352 *	|  |  | K6 |  | K3 |
    353 *	|  |  +----+  +----+
    354 *	  .....
    355 */
    356static struct gpio_keys_button mini2440_buttons[] = {
    357	{
    358		.gpio		= S3C2410_GPG(0),		/* K1 */
    359		.code		= KEY_F1,
    360		.desc		= "Button 1",
    361		.active_low	= 1,
    362	},
    363	{
    364		.gpio		= S3C2410_GPG(3),		/* K2 */
    365		.code		= KEY_F2,
    366		.desc		= "Button 2",
    367		.active_low	= 1,
    368	},
    369	{
    370		.gpio		= S3C2410_GPG(5),		/* K3 */
    371		.code		= KEY_F3,
    372		.desc		= "Button 3",
    373		.active_low	= 1,
    374	},
    375	{
    376		.gpio		= S3C2410_GPG(6),		/* K4 */
    377		.code		= KEY_POWER,
    378		.desc		= "Power",
    379		.active_low	= 1,
    380	},
    381	{
    382		.gpio		= S3C2410_GPG(7),		/* K5 */
    383		.code		= KEY_F5,
    384		.desc		= "Button 5",
    385		.active_low	= 1,
    386	},
    387#if 0
    388	/* this pin is also known as TCLK1 and seems to already
    389	 * marked as "in use" somehow in the kernel -- possibly wrongly
    390	 */
    391	{
    392		.gpio		= S3C2410_GPG(11),	/* K6 */
    393		.code		= KEY_F6,
    394		.desc		= "Button 6",
    395		.active_low	= 1,
    396	},
    397#endif
    398};
    399
    400static struct gpio_keys_platform_data mini2440_button_data = {
    401	.buttons	= mini2440_buttons,
    402	.nbuttons	= ARRAY_SIZE(mini2440_buttons),
    403};
    404
    405static struct platform_device mini2440_button_device = {
    406	.name		= "gpio-keys",
    407	.id		= -1,
    408	.dev		= {
    409		.platform_data	= &mini2440_button_data,
    410	}
    411};
    412
    413/* LEDS */
    414
    415static struct gpiod_lookup_table mini2440_led1_gpio_table = {
    416	.dev_id = "s3c24xx_led.1",
    417	.table = {
    418		GPIO_LOOKUP("GPB", 5, NULL, GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN),
    419		{ },
    420	},
    421};
    422
    423static struct gpiod_lookup_table mini2440_led2_gpio_table = {
    424	.dev_id = "s3c24xx_led.2",
    425	.table = {
    426		GPIO_LOOKUP("GPB", 6, NULL, GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN),
    427		{ },
    428	},
    429};
    430
    431static struct gpiod_lookup_table mini2440_led3_gpio_table = {
    432	.dev_id = "s3c24xx_led.3",
    433	.table = {
    434		GPIO_LOOKUP("GPB", 7, NULL, GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN),
    435		{ },
    436	},
    437};
    438
    439static struct gpiod_lookup_table mini2440_led4_gpio_table = {
    440	.dev_id = "s3c24xx_led.4",
    441	.table = {
    442		GPIO_LOOKUP("GPB", 8, NULL, GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN),
    443		{ },
    444	},
    445};
    446
    447static struct gpiod_lookup_table mini2440_backlight_gpio_table = {
    448	.dev_id = "s3c24xx_led.5",
    449	.table = {
    450		GPIO_LOOKUP("GPG", 4, NULL, GPIO_ACTIVE_HIGH),
    451		{ },
    452	},
    453};
    454
    455static struct s3c24xx_led_platdata mini2440_led1_pdata = {
    456	.name		= "led1",
    457	.def_trigger	= "heartbeat",
    458};
    459
    460static struct s3c24xx_led_platdata mini2440_led2_pdata = {
    461	.name		= "led2",
    462	.def_trigger	= "nand-disk",
    463};
    464
    465static struct s3c24xx_led_platdata mini2440_led3_pdata = {
    466	.name		= "led3",
    467	.def_trigger	= "mmc0",
    468};
    469
    470static struct s3c24xx_led_platdata mini2440_led4_pdata = {
    471	.name		= "led4",
    472	.def_trigger	= "",
    473};
    474
    475static struct s3c24xx_led_platdata mini2440_led_backlight_pdata = {
    476	.name		= "backlight",
    477	.def_trigger	= "backlight",
    478};
    479
    480static struct platform_device mini2440_led1 = {
    481	.name		= "s3c24xx_led",
    482	.id		= 1,
    483	.dev		= {
    484		.platform_data	= &mini2440_led1_pdata,
    485	},
    486};
    487
    488static struct platform_device mini2440_led2 = {
    489	.name		= "s3c24xx_led",
    490	.id		= 2,
    491	.dev		= {
    492		.platform_data	= &mini2440_led2_pdata,
    493	},
    494};
    495
    496static struct platform_device mini2440_led3 = {
    497	.name		= "s3c24xx_led",
    498	.id		= 3,
    499	.dev		= {
    500		.platform_data	= &mini2440_led3_pdata,
    501	},
    502};
    503
    504static struct platform_device mini2440_led4 = {
    505	.name		= "s3c24xx_led",
    506	.id		= 4,
    507	.dev		= {
    508		.platform_data	= &mini2440_led4_pdata,
    509	},
    510};
    511
    512static struct platform_device mini2440_led_backlight = {
    513	.name		= "s3c24xx_led",
    514	.id		= 5,
    515	.dev		= {
    516		.platform_data	= &mini2440_led_backlight_pdata,
    517	},
    518};
    519
    520/* AUDIO */
    521
    522static struct s3c24xx_uda134x_platform_data mini2440_audio_pins = {
    523	.l3_clk = S3C2410_GPB(4),
    524	.l3_mode = S3C2410_GPB(2),
    525	.l3_data = S3C2410_GPB(3),
    526	.model = UDA134X_UDA1341
    527};
    528
    529static struct platform_device mini2440_audio = {
    530	.name		= "s3c24xx_uda134x",
    531	.id		= 0,
    532	.dev		= {
    533		.platform_data	= &mini2440_audio_pins,
    534	},
    535};
    536
    537/*
    538 * I2C devices
    539 */
    540static const struct property_entry mini2440_at24_properties[] = {
    541	PROPERTY_ENTRY_U32("pagesize", 16),
    542	{ }
    543};
    544
    545static const struct software_node mini2440_at24_node = {
    546	.properties = mini2440_at24_properties,
    547};
    548
    549static struct i2c_board_info mini2440_i2c_devs[] __initdata = {
    550	{
    551		I2C_BOARD_INFO("24c08", 0x50),
    552		.swnode = &mini2440_at24_node,
    553	},
    554};
    555
    556static struct uda134x_platform_data s3c24xx_uda134x = {
    557	.l3 = {
    558		.gpio_clk = S3C2410_GPB(4),
    559		.gpio_data = S3C2410_GPB(3),
    560		.gpio_mode = S3C2410_GPB(2),
    561		.use_gpios = 1,
    562		.data_hold = 1,
    563		.data_setup = 1,
    564		.clock_high = 1,
    565		.mode_hold = 1,
    566		.mode = 1,
    567		.mode_setup = 1,
    568	},
    569	.model = UDA134X_UDA1341,
    570};
    571
    572static struct platform_device uda1340_codec = {
    573		.name = "uda134x-codec",
    574		.id = -1,
    575		.dev = {
    576			.platform_data	= &s3c24xx_uda134x,
    577		},
    578};
    579
    580static struct platform_device *mini2440_devices[] __initdata = {
    581	&s3c_device_ohci,
    582	&s3c_device_wdt,
    583	&s3c_device_i2c0,
    584	&s3c_device_rtc,
    585	&s3c_device_usbgadget,
    586	&mini2440_device_eth,
    587	&mini2440_led1,
    588	&mini2440_led2,
    589	&mini2440_led3,
    590	&mini2440_led4,
    591	&mini2440_button_device,
    592	&s3c_device_nand,
    593	&s3c_device_sdi,
    594	&s3c2440_device_dma,
    595	&s3c_device_iis,
    596	&uda1340_codec,
    597	&mini2440_audio,
    598};
    599
    600static void __init mini2440_map_io(void)
    601{
    602	s3c24xx_init_io(mini2440_iodesc, ARRAY_SIZE(mini2440_iodesc));
    603	s3c24xx_init_uarts(mini2440_uartcfgs, ARRAY_SIZE(mini2440_uartcfgs));
    604	s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_PWM4);
    605}
    606
    607static void __init mini2440_init_time(void)
    608{
    609	s3c2440_init_clocks(12000000);
    610	s3c24xx_timer_init();
    611}
    612
    613/*
    614 * mini2440_features string
    615 *
    616 * t = Touchscreen present
    617 * b = backlight control
    618 * c = camera [TODO]
    619 * 0-9 LCD configuration
    620 *
    621 */
    622static char mini2440_features_str[12] __initdata = "0tb";
    623
    624static int __init mini2440_features_setup(char *str)
    625{
    626	if (str)
    627		strlcpy(mini2440_features_str, str,
    628			sizeof(mini2440_features_str));
    629	return 1;
    630}
    631
    632__setup("mini2440=", mini2440_features_setup);
    633
    634#define FEATURE_SCREEN (1 << 0)
    635#define FEATURE_BACKLIGHT (1 << 1)
    636#define FEATURE_TOUCH (1 << 2)
    637#define FEATURE_CAMERA (1 << 3)
    638
    639struct mini2440_features_t {
    640	int count;
    641	int done;
    642	int lcd_index;
    643	struct platform_device *optional[8];
    644};
    645
    646static void __init mini2440_parse_features(
    647		struct mini2440_features_t *features,
    648		const char *features_str)
    649{
    650	const char *fp = features_str;
    651
    652	features->count = 0;
    653	features->done = 0;
    654	features->lcd_index = -1;
    655
    656	while (*fp) {
    657		char f = *fp++;
    658
    659		switch (f) {
    660		case '0'...'9':	/* tft screen */
    661			if (features->done & FEATURE_SCREEN) {
    662				pr_info("MINI2440: '%c' ignored, screen type already set\n",
    663					f);
    664			} else {
    665				int li = f - '0';
    666
    667				if (li >= ARRAY_SIZE(mini2440_lcd_cfg))
    668					pr_info("MINI2440: '%c' out of range LCD mode\n",
    669						f);
    670				else {
    671					features->optional[features->count++] =
    672							&s3c_device_lcd;
    673					features->lcd_index = li;
    674				}
    675			}
    676			features->done |= FEATURE_SCREEN;
    677			break;
    678		case 'b':
    679			if (features->done & FEATURE_BACKLIGHT)
    680				pr_info("MINI2440: '%c' ignored, backlight already set\n",
    681					f);
    682			else {
    683				features->optional[features->count++] =
    684						&mini2440_led_backlight;
    685			}
    686			features->done |= FEATURE_BACKLIGHT;
    687			break;
    688		case 't':
    689			pr_info("MINI2440: '%c' ignored, touchscreen not compiled in\n",
    690				f);
    691			break;
    692		case 'c':
    693			if (features->done & FEATURE_CAMERA)
    694				pr_info("MINI2440: '%c' ignored, camera already registered\n",
    695					f);
    696			else
    697				features->optional[features->count++] =
    698					&s3c_device_camif;
    699			features->done |= FEATURE_CAMERA;
    700			break;
    701		}
    702	}
    703}
    704
    705static void __init mini2440_init(void)
    706{
    707	struct mini2440_features_t features = { 0 };
    708	int i;
    709
    710	pr_info("MINI2440: Option string mini2440=%s\n",
    711			mini2440_features_str);
    712
    713	/* Parse the feature string */
    714	mini2440_parse_features(&features, mini2440_features_str);
    715
    716	/* turn LCD on */
    717	s3c_gpio_cfgpin(S3C2410_GPC(0), S3C2410_GPC0_LEND);
    718
    719	/* Turn the backlight early on */
    720	WARN_ON(gpio_request_one(S3C2410_GPG(4), GPIOF_OUT_INIT_HIGH, NULL));
    721	gpio_free(S3C2410_GPG(4));
    722
    723	/* remove pullup on optional PWM backlight -- unused on 3.5 and 7"s */
    724	gpio_request_one(S3C2410_GPB(1), GPIOF_IN, NULL);
    725	s3c_gpio_setpull(S3C2410_GPB(1), S3C_GPIO_PULL_UP);
    726	gpio_free(S3C2410_GPB(1));
    727
    728	/* mark the key as input, without pullups (there is one on the board) */
    729	for (i = 0; i < ARRAY_SIZE(mini2440_buttons); i++) {
    730		s3c_gpio_setpull(mini2440_buttons[i].gpio, S3C_GPIO_PULL_UP);
    731		s3c_gpio_cfgpin(mini2440_buttons[i].gpio, S3C2410_GPIO_INPUT);
    732	}
    733
    734	/* Configure the I2S pins (GPE0...GPE4) in correct mode */
    735	s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2),
    736			      S3C_GPIO_PULL_NONE);
    737
    738	if (features.lcd_index != -1) {
    739		int li;
    740
    741		mini2440_fb_info.displays =
    742			&mini2440_lcd_cfg[features.lcd_index];
    743
    744		pr_info("MINI2440: LCD");
    745		for (li = 0; li < ARRAY_SIZE(mini2440_lcd_cfg); li++)
    746			if (li == features.lcd_index)
    747				pr_cont(" [%d:%dx%d]", li,
    748					mini2440_lcd_cfg[li].width,
    749					mini2440_lcd_cfg[li].height);
    750			else
    751				pr_cont(" %d:%dx%d", li,
    752					mini2440_lcd_cfg[li].width,
    753					mini2440_lcd_cfg[li].height);
    754		pr_cont("\n");
    755		s3c24xx_fb_set_platdata(&mini2440_fb_info);
    756	}
    757
    758	s3c24xx_udc_set_platdata(&mini2440_udc_cfg);
    759	gpiod_add_lookup_table(&mini2440_mmc_gpio_table);
    760	s3c24xx_mci_set_platdata(&mini2440_mmc_cfg);
    761	s3c_nand_set_platdata(&mini2440_nand_info);
    762	s3c_i2c0_set_platdata(NULL);
    763
    764	i2c_register_board_info(0, mini2440_i2c_devs,
    765				ARRAY_SIZE(mini2440_i2c_devs));
    766
    767	/* Disable pull-up on the LED lines */
    768	s3c_gpio_setpull(S3C2410_GPB(5), S3C_GPIO_PULL_NONE);
    769	s3c_gpio_setpull(S3C2410_GPB(6), S3C_GPIO_PULL_NONE);
    770	s3c_gpio_setpull(S3C2410_GPB(7), S3C_GPIO_PULL_NONE);
    771	s3c_gpio_setpull(S3C2410_GPB(8), S3C_GPIO_PULL_NONE);
    772	s3c_gpio_setpull(S3C2410_GPG(4), S3C_GPIO_PULL_NONE);
    773
    774	/* Add lookups for the lines */
    775	gpiod_add_lookup_table(&mini2440_led1_gpio_table);
    776	gpiod_add_lookup_table(&mini2440_led2_gpio_table);
    777	gpiod_add_lookup_table(&mini2440_led3_gpio_table);
    778	gpiod_add_lookup_table(&mini2440_led4_gpio_table);
    779	gpiod_add_lookup_table(&mini2440_backlight_gpio_table);
    780
    781	platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));
    782
    783	if (features.count)	/* the optional features */
    784		platform_add_devices(features.optional, features.count);
    785
    786}
    787
    788
    789MACHINE_START(MINI2440, "MINI2440")
    790	/* Maintainer: Michel Pollet <buserror@gmail.com> */
    791	.atag_offset	= 0x100,
    792	.nr_irqs	= NR_IRQS_S3C2440,
    793	.map_io		= mini2440_map_io,
    794	.init_machine	= mini2440_init,
    795	.init_irq	= s3c2440_init_irq,
    796	.init_time	= mini2440_init_time,
    797MACHINE_END