Linux Audio

Check our new training course

Linux kernel drivers training

May 6-19, 2025
Register
Loading...
Note: File does not exist in v6.13.7.
   1// SPDX-License-Identifier: GPL-2.0
   2//
   3// Copyright (c) 2011 Samsung Electronics Co., Ltd.
   4//		http://www.samsung.com
   5//
   6// Base Samsung platform device definitions
   7
   8#include <linux/kernel.h>
   9#include <linux/types.h>
  10#include <linux/interrupt.h>
  11#include <linux/list.h>
  12#include <linux/timer.h>
  13#include <linux/init.h>
  14#include <linux/serial_core.h>
  15#include <linux/serial_s3c.h>
  16#include <linux/platform_device.h>
  17#include <linux/io.h>
  18#include <linux/slab.h>
  19#include <linux/string.h>
  20#include <linux/dma-mapping.h>
  21#include <linux/fb.h>
  22#include <linux/gfp.h>
  23#include <linux/mtd/mtd.h>
  24#include <linux/mtd/onenand.h>
  25#include <linux/mtd/partitions.h>
  26#include <linux/mmc/host.h>
  27#include <linux/ioport.h>
  28#include <linux/sizes.h>
  29#include <linux/platform_data/s3c-hsudc.h>
  30#include <linux/platform_data/s3c-hsotg.h>
  31#include <linux/platform_data/dma-s3c24xx.h>
  32
  33#include <linux/platform_data/media/s5p_hdmi.h>
  34
  35#include <asm/irq.h>
  36#include <asm/mach/arch.h>
  37#include <asm/mach/map.h>
  38#include <asm/mach/irq.h>
  39
  40#include <mach/dma.h>
  41#include <mach/irqs.h>
  42#include <mach/map.h>
  43
  44#include <plat/cpu.h>
  45#include <plat/devs.h>
  46#include <plat/adc.h>
  47#include <linux/platform_data/ata-samsung_cf.h>
  48#include <plat/fb.h>
  49#include <plat/fb-s3c2410.h>
  50#include <linux/platform_data/hwmon-s3c.h>
  51#include <linux/platform_data/i2c-s3c2410.h>
  52#include <plat/keypad.h>
  53#include <linux/platform_data/mmc-s3cmci.h>
  54#include <linux/platform_data/mtd-nand-s3c2410.h>
  55#include <plat/pwm-core.h>
  56#include <plat/sdhci.h>
  57#include <linux/platform_data/touchscreen-s3c2410.h>
  58#include <linux/platform_data/usb-s3c2410_udc.h>
  59#include <linux/platform_data/usb-ohci-s3c2410.h>
  60#include <plat/usb-phy.h>
  61#include <plat/regs-spi.h>
  62#include <linux/platform_data/asoc-s3c.h>
  63#include <linux/platform_data/spi-s3c64xx.h>
  64
  65#define samsung_device_dma_mask (*((u64[]) { DMA_BIT_MASK(32) }))
  66
  67/* AC97 */
  68#ifdef CONFIG_CPU_S3C2440
  69static struct resource s3c_ac97_resource[] = {
  70	[0] = DEFINE_RES_MEM(S3C2440_PA_AC97, S3C2440_SZ_AC97),
  71	[1] = DEFINE_RES_IRQ(IRQ_S3C244X_AC97),
  72};
  73
  74struct platform_device s3c_device_ac97 = {
  75	.name		= "samsung-ac97",
  76	.id		= -1,
  77	.num_resources	= ARRAY_SIZE(s3c_ac97_resource),
  78	.resource	= s3c_ac97_resource,
  79	.dev		= {
  80		.dma_mask		= &samsung_device_dma_mask,
  81		.coherent_dma_mask	= DMA_BIT_MASK(32),
  82	}
  83};
  84#endif /* CONFIG_CPU_S3C2440 */
  85
  86/* ADC */
  87
  88#ifdef CONFIG_PLAT_S3C24XX
  89static struct resource s3c_adc_resource[] = {
  90	[0] = DEFINE_RES_MEM(S3C24XX_PA_ADC, S3C24XX_SZ_ADC),
  91	[1] = DEFINE_RES_IRQ(IRQ_TC),
  92	[2] = DEFINE_RES_IRQ(IRQ_ADC),
  93};
  94
  95struct platform_device s3c_device_adc = {
  96	.name		= "s3c24xx-adc",
  97	.id		= -1,
  98	.num_resources	= ARRAY_SIZE(s3c_adc_resource),
  99	.resource	= s3c_adc_resource,
 100};
 101#endif /* CONFIG_PLAT_S3C24XX */
 102
 103#if defined(CONFIG_SAMSUNG_DEV_ADC)
 104static struct resource s3c_adc_resource[] = {
 105	[0] = DEFINE_RES_MEM(SAMSUNG_PA_ADC, SZ_256),
 106	[1] = DEFINE_RES_IRQ(IRQ_ADC),
 107	[2] = DEFINE_RES_IRQ(IRQ_TC),
 108};
 109
 110struct platform_device s3c_device_adc = {
 111	.name		= "exynos-adc",
 112	.id		= -1,
 113	.num_resources	= ARRAY_SIZE(s3c_adc_resource),
 114	.resource	= s3c_adc_resource,
 115};
 116#endif /* CONFIG_SAMSUNG_DEV_ADC */
 117
 118/* Camif Controller */
 119
 120#ifdef CONFIG_CPU_S3C2440
 121static struct resource s3c_camif_resource[] = {
 122	[0] = DEFINE_RES_MEM(S3C2440_PA_CAMIF, S3C2440_SZ_CAMIF),
 123	[1] = DEFINE_RES_IRQ(IRQ_S3C2440_CAM_C),
 124	[2] = DEFINE_RES_IRQ(IRQ_S3C2440_CAM_P),
 125};
 126
 127struct platform_device s3c_device_camif = {
 128	.name		= "s3c2440-camif",
 129	.id		= -1,
 130	.num_resources	= ARRAY_SIZE(s3c_camif_resource),
 131	.resource	= s3c_camif_resource,
 132	.dev		= {
 133		.dma_mask		= &samsung_device_dma_mask,
 134		.coherent_dma_mask	= DMA_BIT_MASK(32),
 135	}
 136};
 137#endif /* CONFIG_CPU_S3C2440 */
 138
 139/* FB */
 140
 141#ifdef CONFIG_S3C_DEV_FB
 142static struct resource s3c_fb_resource[] = {
 143	[0] = DEFINE_RES_MEM(S3C_PA_FB, SZ_16K),
 144	[1] = DEFINE_RES_IRQ(IRQ_LCD_VSYNC),
 145	[2] = DEFINE_RES_IRQ(IRQ_LCD_FIFO),
 146	[3] = DEFINE_RES_IRQ(IRQ_LCD_SYSTEM),
 147};
 148
 149struct platform_device s3c_device_fb = {
 150	.name		= "s3c-fb",
 151	.id		= -1,
 152	.num_resources	= ARRAY_SIZE(s3c_fb_resource),
 153	.resource	= s3c_fb_resource,
 154	.dev		= {
 155		.dma_mask		= &samsung_device_dma_mask,
 156		.coherent_dma_mask	= DMA_BIT_MASK(32),
 157	},
 158};
 159
 160void __init s3c_fb_set_platdata(struct s3c_fb_platdata *pd)
 161{
 162	s3c_set_platdata(pd, sizeof(struct s3c_fb_platdata),
 163			 &s3c_device_fb);
 164}
 165#endif /* CONFIG_S3C_DEV_FB */
 166
 167/* HWMON */
 168
 169#ifdef CONFIG_S3C_DEV_HWMON
 170struct platform_device s3c_device_hwmon = {
 171	.name		= "s3c-hwmon",
 172	.id		= -1,
 173	.dev.parent	= &s3c_device_adc.dev,
 174};
 175
 176void __init s3c_hwmon_set_platdata(struct s3c_hwmon_pdata *pd)
 177{
 178	s3c_set_platdata(pd, sizeof(struct s3c_hwmon_pdata),
 179			 &s3c_device_hwmon);
 180}
 181#endif /* CONFIG_S3C_DEV_HWMON */
 182
 183/* HSMMC */
 184
 185#ifdef CONFIG_S3C_DEV_HSMMC
 186static struct resource s3c_hsmmc_resource[] = {
 187	[0] = DEFINE_RES_MEM(S3C_PA_HSMMC0, SZ_4K),
 188	[1] = DEFINE_RES_IRQ(IRQ_HSMMC0),
 189};
 190
 191struct s3c_sdhci_platdata s3c_hsmmc0_def_platdata = {
 192	.max_width	= 4,
 193	.host_caps	= (MMC_CAP_4_BIT_DATA |
 194			   MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED),
 195};
 196
 197struct platform_device s3c_device_hsmmc0 = {
 198	.name		= "s3c-sdhci",
 199	.id		= 0,
 200	.num_resources	= ARRAY_SIZE(s3c_hsmmc_resource),
 201	.resource	= s3c_hsmmc_resource,
 202	.dev		= {
 203		.dma_mask		= &samsung_device_dma_mask,
 204		.coherent_dma_mask	= DMA_BIT_MASK(32),
 205		.platform_data		= &s3c_hsmmc0_def_platdata,
 206	},
 207};
 208
 209void s3c_sdhci0_set_platdata(struct s3c_sdhci_platdata *pd)
 210{
 211	s3c_sdhci_set_platdata(pd, &s3c_hsmmc0_def_platdata);
 212}
 213#endif /* CONFIG_S3C_DEV_HSMMC */
 214
 215#ifdef CONFIG_S3C_DEV_HSMMC1
 216static struct resource s3c_hsmmc1_resource[] = {
 217	[0] = DEFINE_RES_MEM(S3C_PA_HSMMC1, SZ_4K),
 218	[1] = DEFINE_RES_IRQ(IRQ_HSMMC1),
 219};
 220
 221struct s3c_sdhci_platdata s3c_hsmmc1_def_platdata = {
 222	.max_width	= 4,
 223	.host_caps	= (MMC_CAP_4_BIT_DATA |
 224			   MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED),
 225};
 226
 227struct platform_device s3c_device_hsmmc1 = {
 228	.name		= "s3c-sdhci",
 229	.id		= 1,
 230	.num_resources	= ARRAY_SIZE(s3c_hsmmc1_resource),
 231	.resource	= s3c_hsmmc1_resource,
 232	.dev		= {
 233		.dma_mask		= &samsung_device_dma_mask,
 234		.coherent_dma_mask	= DMA_BIT_MASK(32),
 235		.platform_data		= &s3c_hsmmc1_def_platdata,
 236	},
 237};
 238
 239void s3c_sdhci1_set_platdata(struct s3c_sdhci_platdata *pd)
 240{
 241	s3c_sdhci_set_platdata(pd, &s3c_hsmmc1_def_platdata);
 242}
 243#endif /* CONFIG_S3C_DEV_HSMMC1 */
 244
 245/* HSMMC2 */
 246
 247#ifdef CONFIG_S3C_DEV_HSMMC2
 248static struct resource s3c_hsmmc2_resource[] = {
 249	[0] = DEFINE_RES_MEM(S3C_PA_HSMMC2, SZ_4K),
 250	[1] = DEFINE_RES_IRQ(IRQ_HSMMC2),
 251};
 252
 253struct s3c_sdhci_platdata s3c_hsmmc2_def_platdata = {
 254	.max_width	= 4,
 255	.host_caps	= (MMC_CAP_4_BIT_DATA |
 256			   MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED),
 257};
 258
 259struct platform_device s3c_device_hsmmc2 = {
 260	.name		= "s3c-sdhci",
 261	.id		= 2,
 262	.num_resources	= ARRAY_SIZE(s3c_hsmmc2_resource),
 263	.resource	= s3c_hsmmc2_resource,
 264	.dev		= {
 265		.dma_mask		= &samsung_device_dma_mask,
 266		.coherent_dma_mask	= DMA_BIT_MASK(32),
 267		.platform_data		= &s3c_hsmmc2_def_platdata,
 268	},
 269};
 270
 271void s3c_sdhci2_set_platdata(struct s3c_sdhci_platdata *pd)
 272{
 273	s3c_sdhci_set_platdata(pd, &s3c_hsmmc2_def_platdata);
 274}
 275#endif /* CONFIG_S3C_DEV_HSMMC2 */
 276
 277#ifdef CONFIG_S3C_DEV_HSMMC3
 278static struct resource s3c_hsmmc3_resource[] = {
 279	[0] = DEFINE_RES_MEM(S3C_PA_HSMMC3, SZ_4K),
 280	[1] = DEFINE_RES_IRQ(IRQ_HSMMC3),
 281};
 282
 283struct s3c_sdhci_platdata s3c_hsmmc3_def_platdata = {
 284	.max_width	= 4,
 285	.host_caps	= (MMC_CAP_4_BIT_DATA |
 286			   MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED),
 287};
 288
 289struct platform_device s3c_device_hsmmc3 = {
 290	.name		= "s3c-sdhci",
 291	.id		= 3,
 292	.num_resources	= ARRAY_SIZE(s3c_hsmmc3_resource),
 293	.resource	= s3c_hsmmc3_resource,
 294	.dev		= {
 295		.dma_mask		= &samsung_device_dma_mask,
 296		.coherent_dma_mask	= DMA_BIT_MASK(32),
 297		.platform_data		= &s3c_hsmmc3_def_platdata,
 298	},
 299};
 300
 301void s3c_sdhci3_set_platdata(struct s3c_sdhci_platdata *pd)
 302{
 303	s3c_sdhci_set_platdata(pd, &s3c_hsmmc3_def_platdata);
 304}
 305#endif /* CONFIG_S3C_DEV_HSMMC3 */
 306
 307/* I2C */
 308
 309static struct resource s3c_i2c0_resource[] = {
 310	[0] = DEFINE_RES_MEM(S3C_PA_IIC, SZ_4K),
 311	[1] = DEFINE_RES_IRQ(IRQ_IIC),
 312};
 313
 314struct platform_device s3c_device_i2c0 = {
 315	.name		= "s3c2410-i2c",
 316	.id		= 0,
 317	.num_resources	= ARRAY_SIZE(s3c_i2c0_resource),
 318	.resource	= s3c_i2c0_resource,
 319};
 320
 321struct s3c2410_platform_i2c default_i2c_data __initdata = {
 322	.flags		= 0,
 323	.slave_addr	= 0x10,
 324	.frequency	= 100*1000,
 325	.sda_delay	= 100,
 326};
 327
 328void __init s3c_i2c0_set_platdata(struct s3c2410_platform_i2c *pd)
 329{
 330	struct s3c2410_platform_i2c *npd;
 331
 332	if (!pd) {
 333		pd = &default_i2c_data;
 334		pd->bus_num = 0;
 335	}
 336
 337	npd = s3c_set_platdata(pd, sizeof(*npd), &s3c_device_i2c0);
 338
 339	if (!npd->cfg_gpio)
 340		npd->cfg_gpio = s3c_i2c0_cfg_gpio;
 341}
 342
 343#ifdef CONFIG_S3C_DEV_I2C1
 344static struct resource s3c_i2c1_resource[] = {
 345	[0] = DEFINE_RES_MEM(S3C_PA_IIC1, SZ_4K),
 346	[1] = DEFINE_RES_IRQ(IRQ_IIC1),
 347};
 348
 349struct platform_device s3c_device_i2c1 = {
 350	.name		= "s3c2410-i2c",
 351	.id		= 1,
 352	.num_resources	= ARRAY_SIZE(s3c_i2c1_resource),
 353	.resource	= s3c_i2c1_resource,
 354};
 355
 356void __init s3c_i2c1_set_platdata(struct s3c2410_platform_i2c *pd)
 357{
 358	struct s3c2410_platform_i2c *npd;
 359
 360	if (!pd) {
 361		pd = &default_i2c_data;
 362		pd->bus_num = 1;
 363	}
 364
 365	npd = s3c_set_platdata(pd, sizeof(*npd), &s3c_device_i2c1);
 366
 367	if (!npd->cfg_gpio)
 368		npd->cfg_gpio = s3c_i2c1_cfg_gpio;
 369}
 370#endif /* CONFIG_S3C_DEV_I2C1 */
 371
 372#ifdef CONFIG_S3C_DEV_I2C2
 373static struct resource s3c_i2c2_resource[] = {
 374	[0] = DEFINE_RES_MEM(S3C_PA_IIC2, SZ_4K),
 375	[1] = DEFINE_RES_IRQ(IRQ_IIC2),
 376};
 377
 378struct platform_device s3c_device_i2c2 = {
 379	.name		= "s3c2410-i2c",
 380	.id		= 2,
 381	.num_resources	= ARRAY_SIZE(s3c_i2c2_resource),
 382	.resource	= s3c_i2c2_resource,
 383};
 384
 385void __init s3c_i2c2_set_platdata(struct s3c2410_platform_i2c *pd)
 386{
 387	struct s3c2410_platform_i2c *npd;
 388
 389	if (!pd) {
 390		pd = &default_i2c_data;
 391		pd->bus_num = 2;
 392	}
 393
 394	npd = s3c_set_platdata(pd, sizeof(*npd), &s3c_device_i2c2);
 395
 396	if (!npd->cfg_gpio)
 397		npd->cfg_gpio = s3c_i2c2_cfg_gpio;
 398}
 399#endif /* CONFIG_S3C_DEV_I2C2 */
 400
 401#ifdef CONFIG_S3C_DEV_I2C3
 402static struct resource s3c_i2c3_resource[] = {
 403	[0] = DEFINE_RES_MEM(S3C_PA_IIC3, SZ_4K),
 404	[1] = DEFINE_RES_IRQ(IRQ_IIC3),
 405};
 406
 407struct platform_device s3c_device_i2c3 = {
 408	.name		= "s3c2440-i2c",
 409	.id		= 3,
 410	.num_resources	= ARRAY_SIZE(s3c_i2c3_resource),
 411	.resource	= s3c_i2c3_resource,
 412};
 413
 414void __init s3c_i2c3_set_platdata(struct s3c2410_platform_i2c *pd)
 415{
 416	struct s3c2410_platform_i2c *npd;
 417
 418	if (!pd) {
 419		pd = &default_i2c_data;
 420		pd->bus_num = 3;
 421	}
 422
 423	npd = s3c_set_platdata(pd, sizeof(*npd), &s3c_device_i2c3);
 424
 425	if (!npd->cfg_gpio)
 426		npd->cfg_gpio = s3c_i2c3_cfg_gpio;
 427}
 428#endif /*CONFIG_S3C_DEV_I2C3 */
 429
 430#ifdef CONFIG_S3C_DEV_I2C4
 431static struct resource s3c_i2c4_resource[] = {
 432	[0] = DEFINE_RES_MEM(S3C_PA_IIC4, SZ_4K),
 433	[1] = DEFINE_RES_IRQ(IRQ_IIC4),
 434};
 435
 436struct platform_device s3c_device_i2c4 = {
 437	.name		= "s3c2440-i2c",
 438	.id		= 4,
 439	.num_resources	= ARRAY_SIZE(s3c_i2c4_resource),
 440	.resource	= s3c_i2c4_resource,
 441};
 442
 443void __init s3c_i2c4_set_platdata(struct s3c2410_platform_i2c *pd)
 444{
 445	struct s3c2410_platform_i2c *npd;
 446
 447	if (!pd) {
 448		pd = &default_i2c_data;
 449		pd->bus_num = 4;
 450	}
 451
 452	npd = s3c_set_platdata(pd, sizeof(*npd), &s3c_device_i2c4);
 453
 454	if (!npd->cfg_gpio)
 455		npd->cfg_gpio = s3c_i2c4_cfg_gpio;
 456}
 457#endif /*CONFIG_S3C_DEV_I2C4 */
 458
 459#ifdef CONFIG_S3C_DEV_I2C5
 460static struct resource s3c_i2c5_resource[] = {
 461	[0] = DEFINE_RES_MEM(S3C_PA_IIC5, SZ_4K),
 462	[1] = DEFINE_RES_IRQ(IRQ_IIC5),
 463};
 464
 465struct platform_device s3c_device_i2c5 = {
 466	.name		= "s3c2440-i2c",
 467	.id		= 5,
 468	.num_resources	= ARRAY_SIZE(s3c_i2c5_resource),
 469	.resource	= s3c_i2c5_resource,
 470};
 471
 472void __init s3c_i2c5_set_platdata(struct s3c2410_platform_i2c *pd)
 473{
 474	struct s3c2410_platform_i2c *npd;
 475
 476	if (!pd) {
 477		pd = &default_i2c_data;
 478		pd->bus_num = 5;
 479	}
 480
 481	npd = s3c_set_platdata(pd, sizeof(*npd), &s3c_device_i2c5);
 482
 483	if (!npd->cfg_gpio)
 484		npd->cfg_gpio = s3c_i2c5_cfg_gpio;
 485}
 486#endif /*CONFIG_S3C_DEV_I2C5 */
 487
 488#ifdef CONFIG_S3C_DEV_I2C6
 489static struct resource s3c_i2c6_resource[] = {
 490	[0] = DEFINE_RES_MEM(S3C_PA_IIC6, SZ_4K),
 491	[1] = DEFINE_RES_IRQ(IRQ_IIC6),
 492};
 493
 494struct platform_device s3c_device_i2c6 = {
 495	.name		= "s3c2440-i2c",
 496	.id		= 6,
 497	.num_resources	= ARRAY_SIZE(s3c_i2c6_resource),
 498	.resource	= s3c_i2c6_resource,
 499};
 500
 501void __init s3c_i2c6_set_platdata(struct s3c2410_platform_i2c *pd)
 502{
 503	struct s3c2410_platform_i2c *npd;
 504
 505	if (!pd) {
 506		pd = &default_i2c_data;
 507		pd->bus_num = 6;
 508	}
 509
 510	npd = s3c_set_platdata(pd, sizeof(*npd), &s3c_device_i2c6);
 511
 512	if (!npd->cfg_gpio)
 513		npd->cfg_gpio = s3c_i2c6_cfg_gpio;
 514}
 515#endif /* CONFIG_S3C_DEV_I2C6 */
 516
 517#ifdef CONFIG_S3C_DEV_I2C7
 518static struct resource s3c_i2c7_resource[] = {
 519	[0] = DEFINE_RES_MEM(S3C_PA_IIC7, SZ_4K),
 520	[1] = DEFINE_RES_IRQ(IRQ_IIC7),
 521};
 522
 523struct platform_device s3c_device_i2c7 = {
 524	.name		= "s3c2440-i2c",
 525	.id		= 7,
 526	.num_resources	= ARRAY_SIZE(s3c_i2c7_resource),
 527	.resource	= s3c_i2c7_resource,
 528};
 529
 530void __init s3c_i2c7_set_platdata(struct s3c2410_platform_i2c *pd)
 531{
 532	struct s3c2410_platform_i2c *npd;
 533
 534	if (!pd) {
 535		pd = &default_i2c_data;
 536		pd->bus_num = 7;
 537	}
 538
 539	npd = s3c_set_platdata(pd, sizeof(*npd), &s3c_device_i2c7);
 540
 541	if (!npd->cfg_gpio)
 542		npd->cfg_gpio = s3c_i2c7_cfg_gpio;
 543}
 544#endif /* CONFIG_S3C_DEV_I2C7 */
 545
 546/* I2S */
 547
 548#ifdef CONFIG_PLAT_S3C24XX
 549static struct resource s3c_iis_resource[] = {
 550	[0] = DEFINE_RES_MEM(S3C24XX_PA_IIS, S3C24XX_SZ_IIS),
 551};
 552
 553struct platform_device s3c_device_iis = {
 554	.name		= "s3c24xx-iis",
 555	.id		= -1,
 556	.num_resources	= ARRAY_SIZE(s3c_iis_resource),
 557	.resource	= s3c_iis_resource,
 558	.dev		= {
 559		.dma_mask		= &samsung_device_dma_mask,
 560		.coherent_dma_mask	= DMA_BIT_MASK(32),
 561	}
 562};
 563#endif /* CONFIG_PLAT_S3C24XX */
 564
 565/* IDE CFCON */
 566
 567#ifdef CONFIG_SAMSUNG_DEV_IDE
 568static struct resource s3c_cfcon_resource[] = {
 569	[0] = DEFINE_RES_MEM(SAMSUNG_PA_CFCON, SZ_16K),
 570	[1] = DEFINE_RES_IRQ(IRQ_CFCON),
 571};
 572
 573struct platform_device s3c_device_cfcon = {
 574	.id		= 0,
 575	.num_resources	= ARRAY_SIZE(s3c_cfcon_resource),
 576	.resource	= s3c_cfcon_resource,
 577};
 578
 579void __init s3c_ide_set_platdata(struct s3c_ide_platdata *pdata)
 580{
 581	s3c_set_platdata(pdata, sizeof(struct s3c_ide_platdata),
 582			 &s3c_device_cfcon);
 583}
 584#endif /* CONFIG_SAMSUNG_DEV_IDE */
 585
 586/* KEYPAD */
 587
 588#ifdef CONFIG_SAMSUNG_DEV_KEYPAD
 589static struct resource samsung_keypad_resources[] = {
 590	[0] = DEFINE_RES_MEM(SAMSUNG_PA_KEYPAD, SZ_32),
 591	[1] = DEFINE_RES_IRQ(IRQ_KEYPAD),
 592};
 593
 594struct platform_device samsung_device_keypad = {
 595	.name		= "samsung-keypad",
 596	.id		= -1,
 597	.num_resources	= ARRAY_SIZE(samsung_keypad_resources),
 598	.resource	= samsung_keypad_resources,
 599};
 600
 601void __init samsung_keypad_set_platdata(struct samsung_keypad_platdata *pd)
 602{
 603	struct samsung_keypad_platdata *npd;
 604
 605	npd = s3c_set_platdata(pd, sizeof(*npd), &samsung_device_keypad);
 606
 607	if (!npd->cfg_gpio)
 608		npd->cfg_gpio = samsung_keypad_cfg_gpio;
 609}
 610#endif /* CONFIG_SAMSUNG_DEV_KEYPAD */
 611
 612/* LCD Controller */
 613
 614#ifdef CONFIG_PLAT_S3C24XX
 615static struct resource s3c_lcd_resource[] = {
 616	[0] = DEFINE_RES_MEM(S3C24XX_PA_LCD, S3C24XX_SZ_LCD),
 617	[1] = DEFINE_RES_IRQ(IRQ_LCD),
 618};
 619
 620struct platform_device s3c_device_lcd = {
 621	.name		= "s3c2410-lcd",
 622	.id		= -1,
 623	.num_resources	= ARRAY_SIZE(s3c_lcd_resource),
 624	.resource	= s3c_lcd_resource,
 625	.dev		= {
 626		.dma_mask		= &samsung_device_dma_mask,
 627		.coherent_dma_mask	= DMA_BIT_MASK(32),
 628	}
 629};
 630
 631void __init s3c24xx_fb_set_platdata(struct s3c2410fb_mach_info *pd)
 632{
 633	struct s3c2410fb_mach_info *npd;
 634
 635	npd = s3c_set_platdata(pd, sizeof(*npd), &s3c_device_lcd);
 636	if (npd) {
 637		npd->displays = kmemdup(pd->displays,
 638			sizeof(struct s3c2410fb_display) * npd->num_displays,
 639			GFP_KERNEL);
 640		if (!npd->displays)
 641			printk(KERN_ERR "no memory for LCD display data\n");
 642	} else {
 643		printk(KERN_ERR "no memory for LCD platform data\n");
 644	}
 645}
 646#endif /* CONFIG_PLAT_S3C24XX */
 647
 648/* NAND */
 649
 650#ifdef CONFIG_S3C_DEV_NAND
 651static struct resource s3c_nand_resource[] = {
 652	[0] = DEFINE_RES_MEM(S3C_PA_NAND, SZ_1M),
 653};
 654
 655struct platform_device s3c_device_nand = {
 656	.name		= "s3c2410-nand",
 657	.id		= -1,
 658	.num_resources	= ARRAY_SIZE(s3c_nand_resource),
 659	.resource	= s3c_nand_resource,
 660};
 661
 662/*
 663 * s3c_nand_copy_set() - copy nand set data
 664 * @set: The new structure, directly copied from the old.
 665 *
 666 * Copy all the fields from the NAND set field from what is probably __initdata
 667 * to new kernel memory. The code returns 0 if the copy happened correctly or
 668 * an error code for the calling function to display.
 669 *
 670 * Note, we currently do not try and look to see if we've already copied the
 671 * data in a previous set.
 672 */
 673static int __init s3c_nand_copy_set(struct s3c2410_nand_set *set)
 674{
 675	void *ptr;
 676	int size;
 677
 678	size = sizeof(struct mtd_partition) * set->nr_partitions;
 679	if (size) {
 680		ptr = kmemdup(set->partitions, size, GFP_KERNEL);
 681		set->partitions = ptr;
 682
 683		if (!ptr)
 684			return -ENOMEM;
 685	}
 686
 687	if (set->nr_map && set->nr_chips) {
 688		size = sizeof(int) * set->nr_chips;
 689		ptr = kmemdup(set->nr_map, size, GFP_KERNEL);
 690		set->nr_map = ptr;
 691
 692		if (!ptr)
 693			return -ENOMEM;
 694	}
 695
 696	return 0;
 697}
 698
 699void __init s3c_nand_set_platdata(struct s3c2410_platform_nand *nand)
 700{
 701	struct s3c2410_platform_nand *npd;
 702	int size;
 703	int ret;
 704
 705	/* note, if we get a failure in allocation, we simply drop out of the
 706	 * function. If there is so little memory available at initialisation
 707	 * time then there is little chance the system is going to run.
 708	 */
 709
 710	npd = s3c_set_platdata(nand, sizeof(*npd), &s3c_device_nand);
 711	if (!npd)
 712		return;
 713
 714	/* now see if we need to copy any of the nand set data */
 715
 716	size = sizeof(struct s3c2410_nand_set) * npd->nr_sets;
 717	if (size) {
 718		struct s3c2410_nand_set *from = npd->sets;
 719		struct s3c2410_nand_set *to;
 720		int i;
 721
 722		to = kmemdup(from, size, GFP_KERNEL);
 723		npd->sets = to;	/* set, even if we failed */
 724
 725		if (!to) {
 726			printk(KERN_ERR "%s: no memory for sets\n", __func__);
 727			return;
 728		}
 729
 730		for (i = 0; i < npd->nr_sets; i++) {
 731			ret = s3c_nand_copy_set(to);
 732			if (ret) {
 733				printk(KERN_ERR "%s: failed to copy set %d\n",
 734				__func__, i);
 735				return;
 736			}
 737			to++;
 738		}
 739	}
 740}
 741#endif /* CONFIG_S3C_DEV_NAND */
 742
 743/* ONENAND */
 744
 745#ifdef CONFIG_S3C_DEV_ONENAND
 746static struct resource s3c_onenand_resources[] = {
 747	[0] = DEFINE_RES_MEM(S3C_PA_ONENAND, SZ_1K),
 748	[1] = DEFINE_RES_MEM(S3C_PA_ONENAND_BUF, S3C_SZ_ONENAND_BUF),
 749	[2] = DEFINE_RES_IRQ(IRQ_ONENAND),
 750};
 751
 752struct platform_device s3c_device_onenand = {
 753	.name		= "samsung-onenand",
 754	.id		= 0,
 755	.num_resources	= ARRAY_SIZE(s3c_onenand_resources),
 756	.resource	= s3c_onenand_resources,
 757};
 758#endif /* CONFIG_S3C_DEV_ONENAND */
 759
 760#ifdef CONFIG_S3C64XX_DEV_ONENAND1
 761static struct resource s3c64xx_onenand1_resources[] = {
 762	[0] = DEFINE_RES_MEM(S3C64XX_PA_ONENAND1, SZ_1K),
 763	[1] = DEFINE_RES_MEM(S3C64XX_PA_ONENAND1_BUF, S3C64XX_SZ_ONENAND1_BUF),
 764	[2] = DEFINE_RES_IRQ(IRQ_ONENAND1),
 765};
 766
 767struct platform_device s3c64xx_device_onenand1 = {
 768	.name		= "samsung-onenand",
 769	.id		= 1,
 770	.num_resources	= ARRAY_SIZE(s3c64xx_onenand1_resources),
 771	.resource	= s3c64xx_onenand1_resources,
 772};
 773
 774void __init s3c64xx_onenand1_set_platdata(struct onenand_platform_data *pdata)
 775{
 776	s3c_set_platdata(pdata, sizeof(struct onenand_platform_data),
 777			 &s3c64xx_device_onenand1);
 778}
 779#endif /* CONFIG_S3C64XX_DEV_ONENAND1 */
 780
 781/* PWM Timer */
 782
 783#ifdef CONFIG_SAMSUNG_DEV_PWM
 784static struct resource samsung_pwm_resource[] = {
 785	DEFINE_RES_MEM(SAMSUNG_PA_TIMER, SZ_4K),
 786};
 787
 788struct platform_device samsung_device_pwm = {
 789	.name		= "samsung-pwm",
 790	.id		= -1,
 791	.num_resources	= ARRAY_SIZE(samsung_pwm_resource),
 792	.resource	= samsung_pwm_resource,
 793};
 794
 795void __init samsung_pwm_set_platdata(struct samsung_pwm_variant *pd)
 796{
 797	samsung_device_pwm.dev.platform_data = pd;
 798}
 799#endif /* CONFIG_SAMSUNG_DEV_PWM */
 800
 801/* RTC */
 802
 803#ifdef CONFIG_PLAT_S3C24XX
 804static struct resource s3c_rtc_resource[] = {
 805	[0] = DEFINE_RES_MEM(S3C24XX_PA_RTC, SZ_256),
 806	[1] = DEFINE_RES_IRQ(IRQ_RTC),
 807	[2] = DEFINE_RES_IRQ(IRQ_TICK),
 808};
 809
 810struct platform_device s3c_device_rtc = {
 811	.name		= "s3c2410-rtc",
 812	.id		= -1,
 813	.num_resources	= ARRAY_SIZE(s3c_rtc_resource),
 814	.resource	= s3c_rtc_resource,
 815};
 816#endif /* CONFIG_PLAT_S3C24XX */
 817
 818#ifdef CONFIG_S3C_DEV_RTC
 819static struct resource s3c_rtc_resource[] = {
 820	[0] = DEFINE_RES_MEM(S3C_PA_RTC, SZ_256),
 821	[1] = DEFINE_RES_IRQ(IRQ_RTC_ALARM),
 822	[2] = DEFINE_RES_IRQ(IRQ_RTC_TIC),
 823};
 824
 825struct platform_device s3c_device_rtc = {
 826	.name		= "s3c64xx-rtc",
 827	.id		= -1,
 828	.num_resources	= ARRAY_SIZE(s3c_rtc_resource),
 829	.resource	= s3c_rtc_resource,
 830};
 831#endif /* CONFIG_S3C_DEV_RTC */
 832
 833/* SDI */
 834
 835#ifdef CONFIG_PLAT_S3C24XX
 836static struct resource s3c_sdi_resource[] = {
 837	[0] = DEFINE_RES_MEM(S3C24XX_PA_SDI, S3C24XX_SZ_SDI),
 838	[1] = DEFINE_RES_IRQ(IRQ_SDI),
 839};
 840
 841struct platform_device s3c_device_sdi = {
 842	.name		= "s3c2410-sdi",
 843	.id		= -1,
 844	.num_resources	= ARRAY_SIZE(s3c_sdi_resource),
 845	.resource	= s3c_sdi_resource,
 846};
 847
 848void __init s3c24xx_mci_set_platdata(struct s3c24xx_mci_pdata *pdata)
 849{
 850	s3c_set_platdata(pdata, sizeof(struct s3c24xx_mci_pdata),
 851			 &s3c_device_sdi);
 852}
 853#endif /* CONFIG_PLAT_S3C24XX */
 854
 855/* SPI */
 856
 857#ifdef CONFIG_PLAT_S3C24XX
 858static struct resource s3c_spi0_resource[] = {
 859	[0] = DEFINE_RES_MEM(S3C24XX_PA_SPI, SZ_32),
 860	[1] = DEFINE_RES_IRQ(IRQ_SPI0),
 861};
 862
 863struct platform_device s3c_device_spi0 = {
 864	.name		= "s3c2410-spi",
 865	.id		= 0,
 866	.num_resources	= ARRAY_SIZE(s3c_spi0_resource),
 867	.resource	= s3c_spi0_resource,
 868	.dev		= {
 869		.dma_mask		= &samsung_device_dma_mask,
 870		.coherent_dma_mask	= DMA_BIT_MASK(32),
 871	}
 872};
 873
 874static struct resource s3c_spi1_resource[] = {
 875	[0] = DEFINE_RES_MEM(S3C24XX_PA_SPI1, SZ_32),
 876	[1] = DEFINE_RES_IRQ(IRQ_SPI1),
 877};
 878
 879struct platform_device s3c_device_spi1 = {
 880	.name		= "s3c2410-spi",
 881	.id		= 1,
 882	.num_resources	= ARRAY_SIZE(s3c_spi1_resource),
 883	.resource	= s3c_spi1_resource,
 884	.dev		= {
 885		.dma_mask		= &samsung_device_dma_mask,
 886		.coherent_dma_mask	= DMA_BIT_MASK(32),
 887	}
 888};
 889#endif /* CONFIG_PLAT_S3C24XX */
 890
 891/* Touchscreen */
 892
 893#ifdef CONFIG_PLAT_S3C24XX
 894static struct resource s3c_ts_resource[] = {
 895	[0] = DEFINE_RES_MEM(S3C24XX_PA_ADC, S3C24XX_SZ_ADC),
 896	[1] = DEFINE_RES_IRQ(IRQ_TC),
 897};
 898
 899struct platform_device s3c_device_ts = {
 900	.name		= "s3c2410-ts",
 901	.id		= -1,
 902	.dev.parent	= &s3c_device_adc.dev,
 903	.num_resources	= ARRAY_SIZE(s3c_ts_resource),
 904	.resource	= s3c_ts_resource,
 905};
 906
 907void __init s3c24xx_ts_set_platdata(struct s3c2410_ts_mach_info *hard_s3c2410ts_info)
 908{
 909	s3c_set_platdata(hard_s3c2410ts_info,
 910			 sizeof(struct s3c2410_ts_mach_info), &s3c_device_ts);
 911}
 912#endif /* CONFIG_PLAT_S3C24XX */
 913
 914#ifdef CONFIG_SAMSUNG_DEV_TS
 915static struct s3c2410_ts_mach_info default_ts_data __initdata = {
 916	.delay			= 10000,
 917	.presc			= 49,
 918	.oversampling_shift	= 2,
 919};
 920
 921void __init s3c64xx_ts_set_platdata(struct s3c2410_ts_mach_info *pd)
 922{
 923	if (!pd)
 924		pd = &default_ts_data;
 925
 926	s3c_set_platdata(pd, sizeof(struct s3c2410_ts_mach_info),
 927			 &s3c_device_adc);
 928}
 929#endif /* CONFIG_SAMSUNG_DEV_TS */
 930
 931/* USB */
 932
 933#ifdef CONFIG_S3C_DEV_USB_HOST
 934static struct resource s3c_usb_resource[] = {
 935	[0] = DEFINE_RES_MEM(S3C_PA_USBHOST, SZ_256),
 936	[1] = DEFINE_RES_IRQ(IRQ_USBH),
 937};
 938
 939struct platform_device s3c_device_ohci = {
 940	.name		= "s3c2410-ohci",
 941	.id		= -1,
 942	.num_resources	= ARRAY_SIZE(s3c_usb_resource),
 943	.resource	= s3c_usb_resource,
 944	.dev		= {
 945		.dma_mask		= &samsung_device_dma_mask,
 946		.coherent_dma_mask	= DMA_BIT_MASK(32),
 947	}
 948};
 949
 950/*
 951 * s3c_ohci_set_platdata - initialise OHCI device platform data
 952 * @info: The platform data.
 953 *
 954 * This call copies the @info passed in and sets the device .platform_data
 955 * field to that copy. The @info is copied so that the original can be marked
 956 * __initdata.
 957 */
 958
 959void __init s3c_ohci_set_platdata(struct s3c2410_hcd_info *info)
 960{
 961	s3c_set_platdata(info, sizeof(struct s3c2410_hcd_info),
 962			 &s3c_device_ohci);
 963}
 964#endif /* CONFIG_S3C_DEV_USB_HOST */
 965
 966/* USB Device (Gadget) */
 967
 968#ifdef CONFIG_PLAT_S3C24XX
 969static struct resource s3c_usbgadget_resource[] = {
 970	[0] = DEFINE_RES_MEM(S3C24XX_PA_USBDEV, S3C24XX_SZ_USBDEV),
 971	[1] = DEFINE_RES_IRQ(IRQ_USBD),
 972};
 973
 974struct platform_device s3c_device_usbgadget = {
 975	.name		= "s3c2410-usbgadget",
 976	.id		= -1,
 977	.num_resources	= ARRAY_SIZE(s3c_usbgadget_resource),
 978	.resource	= s3c_usbgadget_resource,
 979};
 980
 981void __init s3c24xx_udc_set_platdata(struct s3c2410_udc_mach_info *pd)
 982{
 983	s3c_set_platdata(pd, sizeof(*pd), &s3c_device_usbgadget);
 984}
 985#endif /* CONFIG_PLAT_S3C24XX */
 986
 987/* USB HSOTG */
 988
 989#ifdef CONFIG_S3C_DEV_USB_HSOTG
 990static struct resource s3c_usb_hsotg_resources[] = {
 991	[0] = DEFINE_RES_MEM(S3C_PA_USB_HSOTG, SZ_128K),
 992	[1] = DEFINE_RES_IRQ(IRQ_OTG),
 993};
 994
 995struct platform_device s3c_device_usb_hsotg = {
 996	.name		= "s3c-hsotg",
 997	.id		= -1,
 998	.num_resources	= ARRAY_SIZE(s3c_usb_hsotg_resources),
 999	.resource	= s3c_usb_hsotg_resources,
1000	.dev		= {
1001		.dma_mask		= &samsung_device_dma_mask,
1002		.coherent_dma_mask	= DMA_BIT_MASK(32),
1003	},
1004};
1005
1006void __init dwc2_hsotg_set_platdata(struct dwc2_hsotg_plat *pd)
1007{
1008	struct dwc2_hsotg_plat *npd;
1009
1010	npd = s3c_set_platdata(pd, sizeof(*npd), &s3c_device_usb_hsotg);
1011
1012	if (!npd->phy_init)
1013		npd->phy_init = s3c_usb_phy_init;
1014	if (!npd->phy_exit)
1015		npd->phy_exit = s3c_usb_phy_exit;
1016}
1017#endif /* CONFIG_S3C_DEV_USB_HSOTG */
1018
1019/* USB High Spped 2.0 Device (Gadget) */
1020
1021#ifdef CONFIG_PLAT_S3C24XX
1022static struct resource s3c_hsudc_resource[] = {
1023	[0] = DEFINE_RES_MEM(S3C2416_PA_HSUDC, S3C2416_SZ_HSUDC),
1024	[1] = DEFINE_RES_IRQ(IRQ_USBD),
1025};
1026
1027struct platform_device s3c_device_usb_hsudc = {
1028	.name		= "s3c-hsudc",
1029	.id		= -1,
1030	.num_resources	= ARRAY_SIZE(s3c_hsudc_resource),
1031	.resource	= s3c_hsudc_resource,
1032	.dev		= {
1033		.dma_mask		= &samsung_device_dma_mask,
1034		.coherent_dma_mask	= DMA_BIT_MASK(32),
1035	},
1036};
1037
1038void __init s3c24xx_hsudc_set_platdata(struct s3c24xx_hsudc_platdata *pd)
1039{
1040	s3c_set_platdata(pd, sizeof(*pd), &s3c_device_usb_hsudc);
1041}
1042#endif /* CONFIG_PLAT_S3C24XX */
1043
1044/* WDT */
1045
1046#ifdef CONFIG_S3C_DEV_WDT
1047static struct resource s3c_wdt_resource[] = {
1048	[0] = DEFINE_RES_MEM(S3C_PA_WDT, SZ_1K),
1049	[1] = DEFINE_RES_IRQ(IRQ_WDT),
1050};
1051
1052struct platform_device s3c_device_wdt = {
1053	.name		= "s3c2410-wdt",
1054	.id		= -1,
1055	.num_resources	= ARRAY_SIZE(s3c_wdt_resource),
1056	.resource	= s3c_wdt_resource,
1057};
1058#endif /* CONFIG_S3C_DEV_WDT */
1059
1060#ifdef CONFIG_S3C64XX_DEV_SPI0
1061static struct resource s3c64xx_spi0_resource[] = {
1062	[0] = DEFINE_RES_MEM(S3C_PA_SPI0, SZ_256),
1063	[1] = DEFINE_RES_IRQ(IRQ_SPI0),
1064};
1065
1066struct platform_device s3c64xx_device_spi0 = {
1067	.name		= "s3c6410-spi",
1068	.id		= 0,
1069	.num_resources	= ARRAY_SIZE(s3c64xx_spi0_resource),
1070	.resource	= s3c64xx_spi0_resource,
1071	.dev = {
1072		.dma_mask		= &samsung_device_dma_mask,
1073		.coherent_dma_mask	= DMA_BIT_MASK(32),
1074	},
1075};
1076
1077void __init s3c64xx_spi0_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
1078						int num_cs)
1079{
1080	struct s3c64xx_spi_info pd;
1081
1082	/* Reject invalid configuration */
1083	if (!num_cs || src_clk_nr < 0) {
1084		pr_err("%s: Invalid SPI configuration\n", __func__);
1085		return;
1086	}
1087
1088	pd.num_cs = num_cs;
1089	pd.src_clk_nr = src_clk_nr;
1090	pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi0_cfg_gpio;
1091
1092	s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi0);
1093}
1094#endif /* CONFIG_S3C64XX_DEV_SPI0 */
1095
1096#ifdef CONFIG_S3C64XX_DEV_SPI1
1097static struct resource s3c64xx_spi1_resource[] = {
1098	[0] = DEFINE_RES_MEM(S3C_PA_SPI1, SZ_256),
1099	[1] = DEFINE_RES_IRQ(IRQ_SPI1),
1100};
1101
1102struct platform_device s3c64xx_device_spi1 = {
1103	.name		= "s3c6410-spi",
1104	.id		= 1,
1105	.num_resources	= ARRAY_SIZE(s3c64xx_spi1_resource),
1106	.resource	= s3c64xx_spi1_resource,
1107	.dev = {
1108		.dma_mask		= &samsung_device_dma_mask,
1109		.coherent_dma_mask	= DMA_BIT_MASK(32),
1110	},
1111};
1112
1113void __init s3c64xx_spi1_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
1114						int num_cs)
1115{
1116	struct s3c64xx_spi_info pd;
1117
1118	/* Reject invalid configuration */
1119	if (!num_cs || src_clk_nr < 0) {
1120		pr_err("%s: Invalid SPI configuration\n", __func__);
1121		return;
1122	}
1123
1124	pd.num_cs = num_cs;
1125	pd.src_clk_nr = src_clk_nr;
1126	pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi1_cfg_gpio;
1127
1128	s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi1);
1129}
1130#endif /* CONFIG_S3C64XX_DEV_SPI1 */
1131
1132#ifdef CONFIG_S3C64XX_DEV_SPI2
1133static struct resource s3c64xx_spi2_resource[] = {
1134	[0] = DEFINE_RES_MEM(S3C_PA_SPI2, SZ_256),
1135	[1] = DEFINE_RES_IRQ(IRQ_SPI2),
1136};
1137
1138struct platform_device s3c64xx_device_spi2 = {
1139	.name		= "s3c6410-spi",
1140	.id		= 2,
1141	.num_resources	= ARRAY_SIZE(s3c64xx_spi2_resource),
1142	.resource	= s3c64xx_spi2_resource,
1143	.dev = {
1144		.dma_mask		= &samsung_device_dma_mask,
1145		.coherent_dma_mask	= DMA_BIT_MASK(32),
1146	},
1147};
1148
1149void __init s3c64xx_spi2_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
1150						int num_cs)
1151{
1152	struct s3c64xx_spi_info pd;
1153
1154	/* Reject invalid configuration */
1155	if (!num_cs || src_clk_nr < 0) {
1156		pr_err("%s: Invalid SPI configuration\n", __func__);
1157		return;
1158	}
1159
1160	pd.num_cs = num_cs;
1161	pd.src_clk_nr = src_clk_nr;
1162	pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi2_cfg_gpio;
1163
1164	s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi2);
1165}
1166#endif /* CONFIG_S3C64XX_DEV_SPI2 */