[RFC PATCH] s5pv210: New samsung SoCs devices support
Kyungmin Park
kmpark at infradead.org
Mon Jul 19 03:33:21 EDT 2010
From: Kyungmin Park <kyungmin.park at samsung.com>
Now only one samsung SoC and its devices are supported in mainline and
can't support several SoCs simultaneously since each SoCs has different memory
address and different number of IPs.
e.g., some 64xx series has 2 I2Cs devices. C1xx series have three I2Cs and
new SoC, S5PV310 has eight I2Cs.
To address these issues. Each devices of SoC are registered at each devices tress (or list) and use it when probe time.
Of course fundamentally we can't compile several SoCs simultaneously at current state. It's just preparation for supporting it
Any comments are welcome.
Thank you,
Kyungmin Park
Here's test codes and results.
static struct samsung_device goni_samsung_devices[] = {
/* device, index */
S5PV210_DEVICE_ID(I2C, 0),
S5PV210_DEVICE_ID(I2C, 1),
S5PV210_DEVICE_ID(I2C, 2),
};
static void __init goni_machine_init(void)
{
samsung_platform_add_devices(goni_samsung_devices,
ARRAY_SIZE(goni_samsung_devices));
platform_add_devices(goni_devices, ARRAY_SIZE(goni_devices));
}
[ 0.140000] samsung 0 device type 0, name s3c2440-i2c, id 2
[ 0.145000] samsung 0 device type 0, name s3c2440-i2c, id 1
[ 0.150000] samsung 0 device type 0, name s3c2440-i2c, id 0
[ 0.155000] S5PV210: Initializing architecture
[ 0.165000] bio: create slab <bio-0> at 0
[ 0.165000] s3c-i2c s3c2440-i2c.0: slave address 0x10
[ 0.170000] s3c-i2c s3c2440-i2c.0: bus frequency set to 378 KHz
[ 0.175000] s3c-i2c s3c2440-i2c.0: i2c-0: S3C I2C adapter
[ 0.185000] s3c-i2c s3c2440-i2c.1: slave address 0x10
[ 0.190000] s3c-i2c s3c2440-i2c.1: bus frequency set to 378 KHz
[ 0.195000] s3c-i2c s3c2440-i2c.1: i2c-1: S3C I2C adapter
[ 0.200000] s3c-i2c s3c2440-i2c.2: slave address 0x10
[ 0.205000] s3c-i2c s3c2440-i2c.2: bus frequency set to 378 KHz
[ 0.210000] s3c-i2c s3c2440-i2c.2: i2c-2: S3C I2C adapter
Signed-off-by: Kyungmin Park <kyungmin.park at samsung.com>
---
mach-s5pv210/Makefile | 1
mach-s5pv210/devices.c | 144 +++++++++++++++++++++++++++++
mach-s5pv210/include/mach/irqs.h | 5 -
plat-samsung/Makefile | 1
plat-samsung/devices.c | 102 ++++++++++++++++++++
plat-samsung/include/plat/samsung_device.h | 53 ++++++++++
6 files changed, 305 insertions(+), 1 deletion(-)
diff --git a/arch/arm/mach-s5pv210/Makefile b/arch/arm/mach-s5pv210/Makefile
index 30be9a6..33ca7eb 100644
--- a/arch/arm/mach-s5pv210/Makefile
+++ b/arch/arm/mach-s5pv210/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_MACH_GONI) += mach-goni.o
# device support
+obj-y += devices.o
obj-y += dev-audio.o
obj-$(CONFIG_S3C64XX_DEV_SPI) += dev-spi.o
obj-$(CONFIG_S5PC110_DEV_ONENAND) += dev-onenand.o
diff --git a/arch/arm/mach-s5pv210/devices.c b/arch/arm/mach-s5pv210/devices.c
new file mode 100644
index 0000000..baf6567
--- /dev/null
+++ b/arch/arm/mach-s5pv210/devices.c
@@ -0,0 +1,144 @@
+/*
+ * arch/arm/mach-s5pv210/devices.c
+ *
+ * Copyright 2010 Samsung Electronics
+ * Kyungmin Park <kyungmin.park at samsung.com>
+ *
+ * Sasmung S5PC110/S5PV210 devices definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+
+#include <mach/map.h>
+#include <plat/gpio-cfg.h>
+#include <plat/samsung_device.h>
+#include <plat/iic.h>
+
+static struct resource s5pv210_i2c0_resource[] = {
+ [0] = {
+ .start = S5PV210_PA_IIC0,
+ .end = S5PV210_PA_IIC0 + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = S5PV210_IRQ_I2C0,
+ .end = S5PV210_IRQ_I2C0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static void s5pv210_i2c0_cfg_gpio(struct platform_device *dev)
+{
+ s3c_gpio_cfgpin(S5PV210_GPD1(0), S3C_GPIO_SFN(2));
+ s3c_gpio_setpull(S5PV210_GPD1(0), S3C_GPIO_PULL_UP);
+ s3c_gpio_cfgpin(S5PV210_GPD1(1), S3C_GPIO_SFN(2));
+ s3c_gpio_setpull(S5PV210_GPD1(1), S3C_GPIO_PULL_UP);
+}
+
+static struct s3c2410_platform_i2c s5pv210_i2c0_data = {
+ .bus_num = 0,
+ .slave_addr = 0x10,
+ .frequency = 400*1000,
+ .sda_delay = 100,
+ .cfg_gpio = s5pv210_i2c0_cfg_gpio,
+};
+
+static struct platform_device s5pv210_i2c0_device = {
+ .name = "s3c2440-i2c",
+ .id = 0,
+ .dev = {
+ .platform_data = &s5pv210_i2c0_data,
+ },
+ .num_resources = ARRAY_SIZE(s5pv210_i2c0_resource),
+ .resource = s5pv210_i2c0_resource,
+};
+
+SAMSUNG_DEVICE_INIT(SAMSUNG_S5PV210, SAMSUNG_DEVICE_I2C, s5pv210_i2c0_device);
+
+static struct resource s5pv210_i2c1_resource[] = {
+ [0] = {
+ .start = S5PV210_PA_IIC1,
+ .end = S5PV210_PA_IIC1 + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = S5PV210_IRQ_I2C1,
+ .end = S5PV210_IRQ_I2C1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static void s5pv210_i2c1_cfg_gpio(struct platform_device *dev)
+{
+ s3c_gpio_cfgpin(S5PV210_GPD1(2), S3C_GPIO_SFN(2));
+ s3c_gpio_setpull(S5PV210_GPD1(2), S3C_GPIO_PULL_UP);
+ s3c_gpio_cfgpin(S5PV210_GPD1(3), S3C_GPIO_SFN(2));
+ s3c_gpio_setpull(S5PV210_GPD1(3), S3C_GPIO_PULL_UP);
+}
+
+static struct s3c2410_platform_i2c s5pv210_i2c1_data = {
+ .bus_num = 1,
+ .slave_addr = 0x10,
+ .frequency = 400*1000,
+ .sda_delay = 100,
+ .cfg_gpio = s5pv210_i2c1_cfg_gpio,
+};
+
+static struct platform_device s5pv210_i2c1_device = {
+ .name = "s3c2440-i2c",
+ .id = 1,
+ .dev = {
+ .platform_data = &s5pv210_i2c1_data,
+ },
+ .num_resources = ARRAY_SIZE(s5pv210_i2c1_resource),
+ .resource = s5pv210_i2c1_resource,
+};
+
+SAMSUNG_DEVICE_INIT(SAMSUNG_S5PV210, SAMSUNG_DEVICE_I2C, s5pv210_i2c1_device);
+
+static struct resource s5pv210_i2c2_resource[] = {
+ [0] = {
+ .start = S5PV210_PA_IIC2,
+ .end = S5PV210_PA_IIC2 + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = S5PV210_IRQ_I2C2,
+ .end = S5PV210_IRQ_I2C2,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static void s5pv210_i2c2_cfg_gpio(struct platform_device *dev)
+{
+ s3c_gpio_cfgpin(S5PV210_GPD1(4), S3C_GPIO_SFN(2));
+ s3c_gpio_setpull(S5PV210_GPD1(4), S3C_GPIO_PULL_UP);
+ s3c_gpio_cfgpin(S5PV210_GPD1(5), S3C_GPIO_SFN(2));
+ s3c_gpio_setpull(S5PV210_GPD1(5), S3C_GPIO_PULL_UP);
+}
+
+static struct s3c2410_platform_i2c s5pv210_i2c2_data = {
+ .bus_num = 2,
+ .slave_addr = 0x10,
+ .frequency = 400*1000,
+ .sda_delay = 100,
+ .cfg_gpio = s5pv210_i2c2_cfg_gpio,
+};
+
+static struct platform_device s5pv210_i2c2_device = {
+ .name = "s3c2440-i2c",
+ .id = 2,
+ .dev = {
+ .platform_data = &s5pv210_i2c2_data,
+ },
+ .num_resources = ARRAY_SIZE(s5pv210_i2c2_resource),
+ .resource = s5pv210_i2c2_resource,
+};
+
+SAMSUNG_DEVICE_INIT(SAMSUNG_S5PV210, SAMSUNG_DEVICE_I2C, s5pv210_i2c2_device);
diff --git a/arch/arm/mach-s5pv210/include/mach/irqs.h b/arch/arm/mach-s5pv210/include/mach/irqs.h
index 9689537..fe48c7f 100644
--- a/arch/arm/mach-s5pv210/include/mach/irqs.h
+++ b/arch/arm/mach-s5pv210/include/mach/irqs.h
@@ -51,11 +51,13 @@
#define IRQ_UART2 S5P_IRQ_VIC1(12)
#define IRQ_UART3 S5P_IRQ_VIC1(13)
#define IRQ_IIC S5P_IRQ_VIC1(14)
+#define S5PV210_IRQ_I2C0 S5P_IRQ_VIC1(14)
#define IRQ_SPI0 S5P_IRQ_VIC1(15)
#define IRQ_SPI1 S5P_IRQ_VIC1(16)
#define IRQ_SPI2 S5P_IRQ_VIC1(17)
#define IRQ_IRDA S5P_IRQ_VIC1(18)
-#define IRQ_CAN0 S5P_IRQ_VIC1(19)
+#define IRQ_IIC2 S5P_IRQ_VIC1(19)
+#define S5PV210_IRQ_I2C2 S5P_IRQ_VIC1(19)
#define IRQ_CAN1 S5P_IRQ_VIC1(20)
#define IRQ_HSIRX S5P_IRQ_VIC1(21)
#define IRQ_HSITX S5P_IRQ_VIC1(22)
@@ -85,6 +87,7 @@
#define IRQ_MIXER S5P_IRQ_VIC2(11)
#define IRQ_HDMI S5P_IRQ_VIC2(12)
#define IRQ_IIC1 S5P_IRQ_VIC2(13)
+#define S5PV210_IRQ_I2C1 S5P_IRQ_VIC2(13)
#define IRQ_MFC S5P_IRQ_VIC2(14)
#define IRQ_TVENC S5P_IRQ_VIC2(15)
#define IRQ_I2S0 S5P_IRQ_VIC2(16)
diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile
index b1d82cc..f2a91f3 100644
--- a/arch/arm/plat-samsung/Makefile
+++ b/arch/arm/plat-samsung/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_S3C_ADC) += adc.o
# devices
+obj-y += devices.o
obj-$(CONFIG_S3C_DEV_HSMMC) += dev-hsmmc.o
obj-$(CONFIG_S3C_DEV_HSMMC1) += dev-hsmmc1.o
obj-$(CONFIG_S3C_DEV_HSMMC2) += dev-hsmmc2.o
diff --git a/arch/arm/plat-samsung/devices.c b/arch/arm/plat-samsung/devices.c
new file mode 100644
index 0000000..0db6555
--- /dev/null
+++ b/arch/arm/plat-samsung/devices.c
@@ -0,0 +1,102 @@
+/*
+ * linux/arch/arm/plat-samsung/devices.c
+ *
+ * Copyright 2010 Samsung Electronics
+ *
+ * Sasmung SoCs series device helper functions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+
+#include <plat/samsung_device.h>
+
+static struct list_head samsung_devices_list[SAMSUNG_NUM_SOC];
+
+static struct samsung_device *samsung_find_device(struct samsung_device *sdev)
+{
+ struct samsung_device *sd;
+
+ list_for_each_entry(sd, &samsung_devices_list[sdev->soc], list) {
+ if (sd->type == sdev->type &&
+ sd->pdev->id == sdev->id) {
+ return sd;
+ }
+ }
+
+ return NULL;
+}
+
+static void samsung_device_unregister(struct samsung_device *sdevs, int num)
+{
+ struct samsung_device *sd;
+ int i;
+
+ for (i = 0; i < num; i++) {
+ sd = samsung_find_device(&sdevs[i]);
+ if (!sd)
+ continue;
+
+ platform_device_unregister(sd->pdev);
+ }
+}
+
+int samsung_platform_add_devices(struct samsung_device *sdevs, int num)
+{
+ struct samsung_device *sd;
+ int i, ret = 0;
+
+ for (i = 0; i < num; i++) {
+ sd = samsung_find_device(&sdevs[i]);
+ if (!sd)
+ continue;
+
+ ret = platform_device_register(sd->pdev);
+ if (ret) {
+ samsung_device_unregister(sdevs, num);
+ break;
+ }
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(samsung_platform_add_devices);
+
+int samsung_device_register(enum samsung_soc soc,
+ enum samsung_device_type type, struct platform_device *pdev)
+{
+ struct samsung_device *sd;
+
+ sd = kzalloc(sizeof(struct samsung_device), GFP_KERNEL);
+ if (!sd)
+ return -ENOMEM;
+
+ printk(KERN_INFO "samsung %d device type %d, name %s, id %d\n",
+ soc, type, pdev->name, pdev->id);
+
+ INIT_LIST_HEAD(&sd->list);
+ sd->soc = soc;
+ sd->type = type;
+ sd->pdev = pdev;
+ list_add(&sd->list, &samsung_devices_list[soc]);
+
+ return 0;
+}
+EXPORT_SYMBOL(samsung_device_register);
+
+static int __init samsung_device_init(void)
+{
+ int i;
+
+ for (i = 0; i < SAMSUNG_NUM_SOC; i++)
+ INIT_LIST_HEAD(&samsung_devices_list[i]);
+ return 0;
+}
+
+pure_initcall(samsung_device_init);
diff --git a/arch/arm/plat-samsung/include/plat/samsung_device.h b/arch/arm/plat-samsung/include/plat/samsung_device.h
new file mode 100644
index 0000000..8bb134a
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/samsung_device.h
@@ -0,0 +1,53 @@
+/*
+ * arch/arm/mach-s5pv210/devices.c
+ *
+ * Copyright 2010 Samsung Electronics
+ * Kyungmin Park <kyungmin.park at samsung.com>
+ *
+ * Sasmung SoCs series devices definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __SAMSUNG_DEVICE_H
+#define __SAMSUNG_DEVICE_H
+
+#include <linux/init.h>
+
+enum samsung_soc {
+ SAMSUNG_S5PV210,
+ SAMSUNG_NUM_SOC,
+};
+
+enum samsung_device_type {
+ SAMSUNG_DEVICE_I2C,
+};
+
+struct samsung_device {
+ struct list_head list;
+ enum samsung_soc soc;
+ enum samsung_device_type type;
+ int id;
+ struct platform_device *pdev;
+};
+
+extern int samsung_platform_add_devices(struct samsung_device *sdevs, int num);
+extern int samsung_device_register(enum samsung_soc soc,
+ enum samsung_device_type type, struct platform_device *pdev);
+
+#define SAMSUNG_DEVICE_ID(dev_soc, dev_type, dev_id) \
+{ .soc = dev_soc, .type = SAMSUNG_DEVICE_##dev_type, .id = dev_id, }
+
+#define S5PV210_DEVICE_ID(dev_type, dev_id) \
+ SAMSUNG_DEVICE_ID(SAMSUNG_S5PV210, dev_type, dev_id)
+
+#define SAMSUNG_DEVICE_INIT(soc, type, pdev) \
+static int samsung_device_init_##pdev(void) \
+{ \
+ return samsung_device_register(soc, type, &pdev); \
+} \
+core_initcall(samsung_device_init_##pdev)
+
+#endif
More information about the linux-arm-kernel
mailing list