Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * Copyright (c) 2005-2008 Simtec Electronics
  3 *	http://armlinux.simtec.co.uk/
  4 *	Ben Dooks <ben@simtec.co.uk>
  5 *
  6 * This program is free software; you can redistribute it and/or modify
  7 * it under the terms of the GNU General Public License version 2 as
  8 * published by the Free Software Foundation.
  9*/
 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/device.h>
 19#include <linux/syscore_ops.h>
 20#include <linux/serial_core.h>
 21#include <linux/serial_s3c.h>
 22#include <linux/clk.h>
 23#include <linux/i2c.h>
 24#include <linux/io.h>
 25#include <linux/platform_device.h>
 26
 27#include <linux/i2c/tps65010.h>
 28
 29#include <asm/mach-types.h>
 30#include <asm/mach/arch.h>
 31#include <asm/mach/map.h>
 32#include <asm/mach/irq.h>
 33#include <asm/irq.h>
 34
 35#include <linux/platform_data/mtd-nand-s3c2410.h>
 36#include <linux/platform_data/i2c-s3c2410.h>
 37
 38#include <linux/mtd/mtd.h>
 39#include <linux/mtd/nand.h>
 40#include <linux/mtd/nand_ecc.h>
 41#include <linux/mtd/partitions.h>
 42
 43#include <plat/clock.h>
 44#include <plat/cpu.h>
 45#include <plat/cpu-freq.h>
 46#include <plat/devs.h>
 47#include <plat/gpio-cfg.h>
 48#include <plat/samsung-time.h>
 49
 50#include <mach/hardware.h>
 51#include <mach/regs-gpio.h>
 52#include <mach/regs-lcd.h>
 53#include <mach/gpio-samsung.h>
 54
 55#include "common.h"
 56#include "osiris.h"
 57#include "regs-mem.h"
 58
 59/* onboard perihperal map */
 60
 61static struct map_desc osiris_iodesc[] __initdata = {
 62  /* ISA IO areas (may be over-written later) */
 63
 64  {
 65	  .virtual	= (u32)S3C24XX_VA_ISA_BYTE,
 66	  .pfn		= __phys_to_pfn(S3C2410_CS5),
 67	  .length	= SZ_16M,
 68	  .type		= MT_DEVICE,
 69  }, {
 70	  .virtual	= (u32)S3C24XX_VA_ISA_WORD,
 71	  .pfn		= __phys_to_pfn(S3C2410_CS5),
 72	  .length	= SZ_16M,
 73	  .type		= MT_DEVICE,
 74  },
 75
 76  /* CPLD control registers */
 77
 78  {
 79	  .virtual	= (u32)OSIRIS_VA_CTRL0,
 80	  .pfn		= __phys_to_pfn(OSIRIS_PA_CTRL0),
 81	  .length	= SZ_16K,
 82	  .type		= MT_DEVICE,
 83  }, {
 84	  .virtual	= (u32)OSIRIS_VA_CTRL1,
 85	  .pfn		= __phys_to_pfn(OSIRIS_PA_CTRL1),
 86	  .length	= SZ_16K,
 87	  .type		= MT_DEVICE,
 88  }, {
 89	  .virtual	= (u32)OSIRIS_VA_CTRL2,
 90	  .pfn		= __phys_to_pfn(OSIRIS_PA_CTRL2),
 91	  .length	= SZ_16K,
 92	  .type		= MT_DEVICE,
 93  }, {
 94	  .virtual	= (u32)OSIRIS_VA_IDREG,
 95	  .pfn		= __phys_to_pfn(OSIRIS_PA_IDREG),
 96	  .length	= SZ_16K,
 97	  .type		= MT_DEVICE,
 98  },
 99};
100
101#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
102#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
103#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
104
105static struct s3c2410_uartcfg osiris_uartcfgs[] __initdata = {
106	[0] = {
107		.hwport	     = 0,
108		.flags	     = 0,
109		.ucon	     = UCON,
110		.ulcon	     = ULCON,
111		.ufcon	     = UFCON,
112		.clk_sel	= S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2,
113	},
114	[1] = {
115		.hwport	     = 1,
116		.flags	     = 0,
117		.ucon	     = UCON,
118		.ulcon	     = ULCON,
119		.ufcon	     = UFCON,
120		.clk_sel	= S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2,
121	},
122	[2] = {
123		.hwport	     = 2,
124		.flags	     = 0,
125		.ucon	     = UCON,
126		.ulcon	     = ULCON,
127		.ufcon	     = UFCON,
128		.clk_sel	= S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2,
129	}
130};
131
132/* NAND Flash on Osiris board */
133
134static int external_map[]   = { 2 };
135static int chip0_map[]      = { 0 };
136static int chip1_map[]      = { 1 };
137
138static struct mtd_partition __initdata osiris_default_nand_part[] = {
139	[0] = {
140		.name	= "Boot Agent",
141		.size	= SZ_16K,
142		.offset	= 0,
143	},
144	[1] = {
145		.name	= "/boot",
146		.size	= SZ_4M - SZ_16K,
147		.offset	= SZ_16K,
148	},
149	[2] = {
150		.name	= "user1",
151		.offset	= SZ_4M,
152		.size	= SZ_32M - SZ_4M,
153	},
154	[3] = {
155		.name	= "user2",
156		.offset	= SZ_32M,
157		.size	= MTDPART_SIZ_FULL,
158	}
159};
160
161static struct mtd_partition __initdata osiris_default_nand_part_large[] = {
162	[0] = {
163		.name	= "Boot Agent",
164		.size	= SZ_128K,
165		.offset	= 0,
166	},
167	[1] = {
168		.name	= "/boot",
169		.size	= SZ_4M - SZ_128K,
170		.offset	= SZ_128K,
171	},
172	[2] = {
173		.name	= "user1",
174		.offset	= SZ_4M,
175		.size	= SZ_32M - SZ_4M,
176	},
177	[3] = {
178		.name	= "user2",
179		.offset	= SZ_32M,
180		.size	= MTDPART_SIZ_FULL,
181	}
182};
183
184/* the Osiris has 3 selectable slots for nand-flash, the two
185 * on-board chip areas, as well as the external slot.
186 *
187 * Note, there is no current hot-plug support for the External
188 * socket.
189*/
190
191static struct s3c2410_nand_set __initdata osiris_nand_sets[] = {
192	[1] = {
193		.name		= "External",
194		.nr_chips	= 1,
195		.nr_map		= external_map,
196		.options	= NAND_SCAN_SILENT_NODEV,
197		.nr_partitions	= ARRAY_SIZE(osiris_default_nand_part),
198		.partitions	= osiris_default_nand_part,
199	},
200	[0] = {
201		.name		= "chip0",
202		.nr_chips	= 1,
203		.nr_map		= chip0_map,
204		.nr_partitions	= ARRAY_SIZE(osiris_default_nand_part),
205		.partitions	= osiris_default_nand_part,
206	},
207	[2] = {
208		.name		= "chip1",
209		.nr_chips	= 1,
210		.nr_map		= chip1_map,
211		.options	= NAND_SCAN_SILENT_NODEV,
212		.nr_partitions	= ARRAY_SIZE(osiris_default_nand_part),
213		.partitions	= osiris_default_nand_part,
214	},
215};
216
217static void osiris_nand_select(struct s3c2410_nand_set *set, int slot)
218{
219	unsigned int tmp;
220
221	slot = set->nr_map[slot] & 3;
222
223	pr_debug("osiris_nand: selecting slot %d (set %p,%p)\n",
224		 slot, set, set->nr_map);
225
226	tmp = __raw_readb(OSIRIS_VA_CTRL0);
227	tmp &= ~OSIRIS_CTRL0_NANDSEL;
228	tmp |= slot;
229
230	pr_debug("osiris_nand: ctrl0 now %02x\n", tmp);
231
232	__raw_writeb(tmp, OSIRIS_VA_CTRL0);
233}
234
235static struct s3c2410_platform_nand __initdata osiris_nand_info = {
236	.tacls		= 25,
237	.twrph0		= 60,
238	.twrph1		= 60,
239	.nr_sets	= ARRAY_SIZE(osiris_nand_sets),
240	.sets		= osiris_nand_sets,
241	.select_chip	= osiris_nand_select,
242};
243
244/* PCMCIA control and configuration */
245
246static struct resource osiris_pcmcia_resource[] = {
247	[0] = DEFINE_RES_MEM(0x0f000000, SZ_1M),
248	[1] = DEFINE_RES_MEM(0x0c000000, SZ_1M),
249};
250
251static struct platform_device osiris_pcmcia = {
252	.name		= "osiris-pcmcia",
253	.id		= -1,
254	.num_resources	= ARRAY_SIZE(osiris_pcmcia_resource),
255	.resource	= osiris_pcmcia_resource,
256};
257
258/* Osiris power management device */
259
260#ifdef CONFIG_PM
261static unsigned char pm_osiris_ctrl0;
262
263static int osiris_pm_suspend(void)
264{
265	unsigned int tmp;
266
267	pm_osiris_ctrl0 = __raw_readb(OSIRIS_VA_CTRL0);
268	tmp = pm_osiris_ctrl0 & ~OSIRIS_CTRL0_NANDSEL;
269
270	/* ensure correct NAND slot is selected on resume */
271	if ((pm_osiris_ctrl0 & OSIRIS_CTRL0_BOOT_INT) == 0)
272	        tmp |= 2;
273
274	__raw_writeb(tmp, OSIRIS_VA_CTRL0);
275
276	/* ensure that an nRESET is not generated on resume. */
277	gpio_request_one(S3C2410_GPA(21), GPIOF_OUT_INIT_HIGH, NULL);
278	gpio_free(S3C2410_GPA(21));
279
280	return 0;
281}
282
283static void osiris_pm_resume(void)
284{
285	if (pm_osiris_ctrl0 & OSIRIS_CTRL0_FIX8)
286		__raw_writeb(OSIRIS_CTRL1_FIX8, OSIRIS_VA_CTRL1);
287
288	__raw_writeb(pm_osiris_ctrl0, OSIRIS_VA_CTRL0);
289
290	s3c_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPA21_nRSTOUT);
291}
292
293#else
294#define osiris_pm_suspend NULL
295#define osiris_pm_resume NULL
296#endif
297
298static struct syscore_ops osiris_pm_syscore_ops = {
299	.suspend	= osiris_pm_suspend,
300	.resume		= osiris_pm_resume,
301};
302
303/* Link for DVS driver to TPS65011 */
304
305static void osiris_tps_release(struct device *dev)
306{
307	/* static device, do not need to release anything */
308}
309
310static struct platform_device osiris_tps_device = {
311	.name	= "osiris-dvs",
312	.id	= -1,
313	.dev.release = osiris_tps_release,
314};
315
316static int osiris_tps_setup(struct i2c_client *client, void *context)
317{
318	osiris_tps_device.dev.parent = &client->dev;
319	return platform_device_register(&osiris_tps_device);
320}
321
322static int osiris_tps_remove(struct i2c_client *client, void *context)
323{
324	platform_device_unregister(&osiris_tps_device);
325	return 0;
326}
327
328static struct tps65010_board osiris_tps_board = {
329	.base		= -1,	/* GPIO can go anywhere at the moment */
330	.setup		= osiris_tps_setup,
331	.teardown	= osiris_tps_remove,
332};
333
334/* I2C devices fitted. */
335
336static struct i2c_board_info osiris_i2c_devs[] __initdata = {
337	{
338		I2C_BOARD_INFO("tps65011", 0x48),
339		.irq	= IRQ_EINT20,
340		.platform_data = &osiris_tps_board,
341	},
342};
343
344/* Standard Osiris devices */
345
346static struct platform_device *osiris_devices[] __initdata = {
347	&s3c_device_i2c0,
348	&s3c_device_wdt,
349	&s3c_device_nand,
350	&osiris_pcmcia,
351};
352
353static struct clk *osiris_clocks[] __initdata = {
354	&s3c24xx_dclk0,
355	&s3c24xx_dclk1,
356	&s3c24xx_clkout0,
357	&s3c24xx_clkout1,
358	&s3c24xx_uclk,
359};
360
361static struct s3c_cpufreq_board __initdata osiris_cpufreq = {
362	.refresh	= 7800, /* refresh period is 7.8usec */
363	.auto_io	= 1,
364	.need_io	= 1,
365};
366
367static void __init osiris_map_io(void)
368{
369	unsigned long flags;
370
371	/* initialise the clocks */
372
373	s3c24xx_dclk0.parent = &clk_upll;
374	s3c24xx_dclk0.rate   = 12*1000*1000;
375
376	s3c24xx_dclk1.parent = &clk_upll;
377	s3c24xx_dclk1.rate   = 24*1000*1000;
378
379	s3c24xx_clkout0.parent  = &s3c24xx_dclk0;
380	s3c24xx_clkout1.parent  = &s3c24xx_dclk1;
381
382	s3c24xx_uclk.parent  = &s3c24xx_clkout1;
383
384	s3c24xx_register_clocks(osiris_clocks, ARRAY_SIZE(osiris_clocks));
385
386	s3c24xx_init_io(osiris_iodesc, ARRAY_SIZE(osiris_iodesc));
387	s3c24xx_init_clocks(0);
388	s3c24xx_init_uarts(osiris_uartcfgs, ARRAY_SIZE(osiris_uartcfgs));
389	samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4);
390
391	/* check for the newer revision boards with large page nand */
392
393	if ((__raw_readb(OSIRIS_VA_IDREG) & OSIRIS_ID_REVMASK) >= 4) {
394		printk(KERN_INFO "OSIRIS-B detected (revision %d)\n",
395		       __raw_readb(OSIRIS_VA_IDREG) & OSIRIS_ID_REVMASK);
396		osiris_nand_sets[0].partitions = osiris_default_nand_part_large;
397		osiris_nand_sets[0].nr_partitions = ARRAY_SIZE(osiris_default_nand_part_large);
398	} else {
399		/* write-protect line to the NAND */
400		gpio_request_one(S3C2410_GPA(0), GPIOF_OUT_INIT_HIGH, NULL);
401		gpio_free(S3C2410_GPA(0));
402	}
403
404	/* fix bus configuration (nBE settings wrong on ABLE pre v2.20) */
405
406	local_irq_save(flags);
407	__raw_writel(__raw_readl(S3C2410_BWSCON) | S3C2410_BWSCON_ST1 | S3C2410_BWSCON_ST2 | S3C2410_BWSCON_ST3 | S3C2410_BWSCON_ST4 | S3C2410_BWSCON_ST5, S3C2410_BWSCON);
408	local_irq_restore(flags);
409}
410
411static void __init osiris_init(void)
412{
413	register_syscore_ops(&osiris_pm_syscore_ops);
414
415	s3c_i2c0_set_platdata(NULL);
416	s3c_nand_set_platdata(&osiris_nand_info);
417
418	s3c_cpufreq_setboard(&osiris_cpufreq);
419
420	i2c_register_board_info(0, osiris_i2c_devs,
421				ARRAY_SIZE(osiris_i2c_devs));
422
423	platform_add_devices(osiris_devices, ARRAY_SIZE(osiris_devices));
424};
425
426MACHINE_START(OSIRIS, "Simtec-OSIRIS")
427	/* Maintainer: Ben Dooks <ben@simtec.co.uk> */
428	.atag_offset	= 0x100,
429	.map_io		= osiris_map_io,
430	.init_irq	= s3c2440_init_irq,
431	.init_machine	= osiris_init,
432	.init_time	= samsung_timer_init,
433	.restart	= s3c244x_restart,
434MACHINE_END