Skip to contentSkip to conversation

omap_device implementation, and HSMMC example

PATCH New Paul Walmsley 1 participant 4 messages Jun 5, 2009

Subsystems (6)
lore
Share & tools
lore
#0 lore raw

cover omap_device implementation, and HSMMC example

Hello,

This patch series implements the first public version of the omap_device code. The basic point of this code is to extend the platform_device code with some features that are suited to OMAP code. Most of these features concern device initialization, resource enumeration, and power management.

The series consists of the core code and data structures, along with an example HSMMC conversion for OMAP2430 and OMAP34xx.

The omap_device code is initially intended for use with OMAP2+ chips. It depends on the omap_hwmod patch series posted earlier -- each omap_device structure is connected to one or more omap_hwmod structures.

A slightly different approach is perhaps best in the long run; either to extend platform_device with subarchitecture-specific hooks to call these functions perhaps along the lines of Magnus Damm's recent proposal, or to replace platform_device/platform_bus with an omap_device/omap_bus layer.

More detailed descriptions are found in each individual patch description.

Boot-tested on OMAP3 Beagle and 3430SDP. Compile-tested on 2430SDP and N800. The code has only been lightly tested, so there are likely to be bugs -- patches and other feedback are welcome and solicited.

- Paul

---

omap_device
text data bss dec hex filename

3417637  194016  104080 3715733  38b295 vmlinux.omap3beagle.orig
3420233  194016  104080 3718329  38bcb9 vmlinux.omap3beagle

Paul Walmsley (3):
OMAP2/3 MMC: initial conversion to omap_device
OMAP: MMC (core): split device registration by OMAP variant OMAP2/3/4 core: create omap_device layer

 arch/arm/mach-omap1/devices.c                 |   41 ++
 arch/arm/mach-omap2/devices.c                 |  104 +++-
 arch/arm/mach-omap2/mmc-twl4030.c             |   12 
 arch/arm/plat-omap/Makefile                   |    6 
 arch/arm/plat-omap/devices.c                  |   50 --
 arch/arm/plat-omap/include/mach/mmc.h         |   11 
 arch/arm/plat-omap/include/mach/omap_device.h |  140 +++++
 arch/arm/plat-omap/omap_device.c              |  654 +++++++++++++++++++++++++
 drivers/mmc/host/omap_hsmmc.c                 |   99 ++--
 9 files changed, 974 insertions(+), 143 deletions(-)
 create mode 100644 arch/arm/plat-omap/include/mach/omap_device.h
 create mode 100644 arch/arm/plat-omap/omap_device.c
#1 lore raw

PATCH 1/3 OMAP2/3/4 core: create omap_device layer

The omap_device code provides a mapping of omap_hwmod structures into the platform_device system, and includes some details on external (board-level) integration. This allows drivers to enable, idle, and shutdown on-chip device resources, including clocks, regulators, etc. The resources enabled and idled are dependent on the device's maximum wakeup latency constraint (if present).

At the moment, omap_device functions are intended to be called from platform_data function pointers. Ideally in the future these functions will be called from either subarchitecture-specific platform_data activate, deactivate functions, or via an custom bus/device type for OMAP.

Cc Benoit Cousson <[email protected]>
Cc Kevin Hilman <[email protected]>
Cc Tony Lindgren <[email protected]>
Cc Rajendra Nayak <[email protected]>
Cc Vikram Pandita <[email protected]>
Cc Sakari Poussa <[email protected]>
Cc Ansnd Sawant <[email protected]>
Cc Santosh Shilimkar <[email protected]>
Cc Eric Thomas <[email protected]>
Cc Richard Woodruff <[email protected]>
---
 arch/arm/plat-omap/Makefile                   |    6 
 arch/arm/plat-omap/include/mach/omap_device.h |  140 +++++
 arch/arm/plat-omap/omap_device.c              |  654 +++++++++++++++++++++++++
 3 files changed, 799 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/plat-omap/include/mach/omap_device.h
 create mode 100644 arch/arm/plat-omap/omap_device.c
arch/arm/plat-omap/Makefile +5 -1
index 3ebc09e..8f9c70b 100644
@@ -4,7 +4,7 @@
 
 # Common support
 obj-y := common.o sram.o clock.o devices.o dma.o mux.o gpio.o \
-	 usb.o fb.o io.o
+	 usb.o fb.o io.o omap_device.o
 obj-m :=
 obj-n :=
 obj-  :=
@@ -12,6 +12,10 @@ obj-  :=
 # OCPI interconnect support for 1710, 1610 and 5912
 obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
 
+# omap_device support (OMAP2+ only at the moment)
+obj-$(CONFIG_ARCH_OMAP2) += omap_device.o
+obj-$(CONFIG_ARCH_OMAP3) += omap_device.o
+
 obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
 
 obj-$(CONFIG_CPU_FREQ) += cpu-omap.o
arch/arm/plat-omap/include/mach/omap_device.h new file +140 -0

140 lines not on this page · raw message

arch/arm/plat-omap/omap_device.c new file +654 -0

654 lines not on this page · raw message

#2 lore raw

PATCH 2/3 OMAP: MMC (core): split device registration by OMAP variant

In reply to Paul Walmsley

Split OMAP-common MMC device registration into OMAP1 and OMAP2 components. This is in preparation for the omap_device conversion of the HSMMC portions.

---
 arch/arm/mach-omap1/devices.c |   41 ++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/devices.c |   46 +++++++++++++++++++++++++++++++++++++-
 arch/arm/plat-omap/devices.c  |   50 -----------------------------------------
 3 files changed, 86 insertions(+), 51 deletions(-)
arch/arm/mach-omap1/devices.c +41 -0
index bbbaeb0..8de7e3f 100644
@@ -104,6 +104,47 @@ static inline void omap_init_mbox(void) { }
 
 #if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
 
+#define OMAP_MMC_NR_RES		2
+
+/* Register MMC devices */
+int __init omap_mmc_add(const char *name, int id, unsigned long base,
+				unsigned long size, unsigned int irq,
+				struct omap_mmc_platform_data *data)
+{
+	struct platform_device *pdev;
+	struct resource res[OMAP_MMC_NR_RES];
+	int ret;
+
+	pdev = platform_device_alloc(name, id);
+	if (!pdev)
+		return -ENOMEM;
+
+	memset(res, 0, OMAP_MMC_NR_RES * sizeof(struct resource));
+	res[0].start = base;
+	res[0].end = base + size - 1;
+	res[0].flags = IORESOURCE_MEM;
+	res[1].start = res[1].end = irq;
+	res[1].flags = IORESOURCE_IRQ;
+
+	ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res));
+	if (ret == 0)
+		ret = platform_device_add_data(pdev, data, sizeof(*data));
+	if (ret)
+		goto fail;
+
+	ret = platform_device_add(pdev);
+	if (ret)
+		goto fail;
+
+	/* return device handle to board setup code */
+	data->dev = &pdev->dev;
+	return 0;
+
+fail:
+	platform_device_put(pdev);
+	return ret;
+}
+
 static inline void omap1_mmc_mux(struct omap_mmc_platform_data *mmc_controller,
 			int controller_nr)
 {
arch/arm/mach-omap2/devices.c +45 -1

58 lines not on this page · raw message

arch/arm/plat-omap/devices.c +0 -50

56 lines not on this page · raw message

#3 lore raw

PATCH 3/3 OMAP2/3 MMC: initial conversion to omap_device

In reply to Paul Walmsley

Convert the HSMMC driver to use omap_device. A notable aspect of this is that the use of the dev_attr data from the omap_hwmod allows the redaction of all of the integration-specific hacks inside this driver. Regulator control has not yet been converted; the driver still uses the platform_data set_power hook.

Note that the non-HS MMC driver, used on 2420 and previous, has not yet been converted.

---
 arch/arm/mach-omap2/devices.c         |  146 ++++++++++++++++-----------------
 arch/arm/mach-omap2/mmc-twl4030.c     |   12 ++-
 arch/arm/plat-omap/include/mach/mmc.h |   11 ++
 drivers/mmc/host/omap_hsmmc.c         |   99 ++++++++++------------
 4 files changed, 133 insertions(+), 135 deletions(-)
arch/arm/mach-omap2/devices.c +69 -77
index 4a64a4c..ebfe678 100644
@@ -15,6 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/clk.h>
+#include <linux/err.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -27,6 +28,9 @@
 #include <mach/gpio.h>
 #include <mach/mmc.h>
 
+#include <mach/omap_device.h>
+#include <mach/omap_hwmod.h>
+
 #if defined(CONFIG_VIDEO_OMAP2) || defined(CONFIG_VIDEO_OMAP2_MODULE)
 
 static struct resource cam_resources[] = {
@@ -484,6 +488,28 @@ static inline void omap_hsmmc_reset(void) {}
 #if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \
 	defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
 
+/*
+ * XXX Eventually this latency data should be pushed into the
+ * corresponding data: e.g., clock data, regulator data, etc.  Several
+ * devices may share regulators, which can make these latencies less
+ * useful.
+ *
+ * XXX These latency numbers are wrong.  Replace them with measured latency
+ * data.
+ */
+static struct omap_device_pm_latency omap_hsmmc_latency[] = {
+	[0] = {
+		.deactivate_lat	 = 1,
+		.deactivate_func = omap_device_idle_hwmods,
+		.activate_lat	 = 1,
+		.activate_func	 = omap_device_enable_hwmods,
+	},
+	/*
+	 * XXX There should also be an entry here to power off/on the
+	 * MMC regulators/PBIAS cells, etc.
+	 */
+};
+
 static inline void omap2_mmc_mux(struct omap_mmc_platform_data *mmc_controller,
 			int controller_nr)
 {
@@ -515,94 +541,60 @@ static inline void omap2_mmc_mux(struct omap_mmc_platform_data *mmc_controller,
 	}
 }
 
-#define OMAP_MMC_NR_RES		2
-
-/*
- * Register MMC devices. Called from mach-omap1 and mach-omap2 device init.
- */
-int __init omap2_mmc_add(const char *name, int id, unsigned long base,
-				unsigned long size, unsigned int irq,
-				struct omap_mmc_platform_data *data)
-{
-	struct platform_device *pdev;
-	struct resource res[OMAP_MMC_NR_RES];
-	int ret;
-
-	pdev = platform_device_alloc(name, id);
-	if (!pdev)
-		return -ENOMEM;
-
-	memset(res, 0, OMAP_MMC_NR_RES * sizeof(struct resource));
-	res[0].start = base;
-	res[0].end = base + size - 1;
-	res[0].flags = IORESOURCE_MEM;
-	res[1].start = res[1].end = irq;
-	res[1].flags = IORESOURCE_IRQ;
-
-	ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res));
-	if (ret == 0)
-		ret = platform_device_add_data(pdev, data, sizeof(*data));
-	if (ret)
-		goto fail;
-
-	ret = platform_device_add(pdev);
-	if (ret)
-		goto fail;
-
-	/* return device handle to board setup code */
-	data->dev = &pdev->dev;
-	return 0;
-
-fail:
-	platform_device_put(pdev);
-	return ret;
-}
-
+#define MAX_OMAP_MMC_HWMOD_NAME_LEN		16
 
 void __init omap2_init_mmc(struct omap_mmc_platform_data **mmc_data,
-			int nr_controllers)
+			   int nr_controllers)
 {
-	int i;
+	struct omap_hwmod *oh;
+	struct omap_device *od;
+	struct omap_device_pm_latency *ohl;
+	char oh_name[MAX_OMAP_MMC_HWMOD_NAME_LEN];
 	char *name;
+	int i, l;
+	int ohl_cnt = 0;
 
-	for (i = 0; i < nr_controllers; i++) {
-		unsigned long base, size;
-		unsigned int irq = 0;
+	if (cpu_is_omap2420()) {
+		name = "mmci-omap";
+	} else {
+		name = "mmci-omap-hs";
+		ohl = omap_hsmmc_latency;
+		ohl_cnt = ARRAY_SIZE(omap_hsmmc_latency);
+	}
 
-		if (!mmc_data[i])
+	/*
+	 * XXX This isn't a good way to set these up.  What if a board
+	 * uses MMC2 but not MMC1?
+	 */
+	for (i = 1; i <= nr_controllers; i++) {
+		int idx = i - 1;
+
+		l = snprintf(oh_name, MAX_OMAP_MMC_HWMOD_NAME_LEN,
+			     "mmc%d_hwmod", i);
+		WARN(l >= MAX_OMAP_MMC_HWMOD_NAME_LEN,
+		     "String buffer overflow in MMC%d device setup\n", i);
+		oh = omap_hwmod_lookup(oh_name);
+		if (!oh) {
+			pr_err("Could not look up %s\n", oh_name);
 			continue;
+		}
 
-		omap2_mmc_mux(mmc_data[i], i);
+		mmc_data[idx]->dev_attr = oh->dev_attr;
 
-		switch (i) {
-		case 0:
-			base = OMAP2_MMC1_BASE;
-			irq = INT_24XX_MMC_IRQ;
-			break;
-		case 1:
-			base = OMAP2_MMC2_BASE;
-			irq = INT_24XX_MMC2_IRQ;
-			break;
-		case 2:
-			if (!cpu_is_omap34xx())
-				return;
-			base = OMAP3_MMC3_BASE;
-			irq = INT_34XX_MMC3_IRQ;
-			break;
-		default:
-			continue;
-		}
+		omap2_mmc_mux(mmc_data[idx], idx);
+		od = omap_device_build(name, idx, oh, mmc_data[idx],
+				       sizeof(struct omap_mmc_platform_data),
+				       ohl, ohl_cnt);
+		WARN(IS_ERR(od), "Could not build omap_device for %s %s\n",
+		     name, oh_name);
 
-		if (cpu_is_omap2420()) {
-			size = OMAP2420_MMC_SIZE;
-			name = "mmci-omap";
-		} else {
-			size = HSMMC_SIZE;
-			name = "mmci-omap-hs";
-		}
-		omap2_mmc_add(name, i, base, size, irq, mmc_data[i]);
+		/*
+		 * return device handle to board setup code
+		 * XXX Can this be removed?
+		 */
+		mmc_data[idx]->dev = &od->pdev.dev;
 	};
-}
+};
 
 #endif
 
arch/arm/mach-omap2/mmc-twl4030.c +10 -2
index 886066b..84093ec 100644
@@ -2,7 +2,7 @@
  * linux/arch/arm/mach-omap2/mmc-twl4030.c
  *
  * Copyright (C) 2007-2008 Texas Instruments
- * Copyright (C) 2008 Nokia Corporation
+ * Copyright (C) 2008-2009 Nokia Corporation
  * Author: Texas Instruments
  *
  * This program is free software; you can redistribute it and/or modify
@@ -23,6 +23,7 @@
 #include <mach/control.h>
 #include <mach/mmc.h>
 #include <mach/board.h>
+#include <mach/omap_device.h>
 
 #include "mmc-twl4030.h"
 
@@ -328,6 +329,7 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers)
 {
 	struct twl4030_hsmmc_info *c;
 	int nr_hsmmc = ARRAY_SIZE(hsmmc_data);
+	int controller_cnt = 0;
 
 	if (cpu_is_omap2430()) {
 		control_pbias_offset = OMAP243X_CONTROL_PBIAS_LITE;
@@ -351,6 +353,8 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers)
 			continue;
 		}
 
+		controller_cnt++;
+
 		mmc = kzalloc(sizeof(struct omap_mmc_platform_data), GFP_KERNEL);
 		if (!mmc) {
 			pr_err("Cannot allocate memory for mmc device!\n");
@@ -369,6 +373,10 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers)
 		mmc->dma_mask = 0xffffffff;
 		mmc->init = twl_mmc_late_init;
 
+		mmc->device_enable = omap_device_enable;
+		mmc->device_shutdown = omap_device_shutdown;
+		mmc->device_idle = omap_device_idle;
+
 		/* note: twl4030 card detect GPIOs can disable VMMCx ... */
 		if (gpio_is_valid(c->gpio_cd)) {
 			mmc->cleanup = twl_mmc_cleanup;
@@ -425,7 +433,7 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers)
 		hsmmc_data[c->mmc - 1] = mmc;
 	}
 
-	omap2_init_mmc(hsmmc_data, OMAP34XX_NR_MMC);
+	omap2_init_mmc(hsmmc_data, controller_cnt);
 
 	/* pass the device nodes back to board setup code */
 	for (c = controllers; c->mmc; c++) {
arch/arm/plat-omap/include/mach/mmc.h +11 -0
index 4996a54..99fe3e1 100644
@@ -14,9 +14,12 @@
 #include <linux/types.h>
 #include <linux/device.h>
 #include <linux/mmc/host.h>
+#include <linux/platform_device.h>
 
 #include <mach/board.h>
 
+#include <mach/omap_hwmod.h>
+
 #define OMAP15XX_NR_MMC		1
 #define OMAP16XX_NR_MMC		2
 #define OMAP1_MMC_SIZE		0x080
@@ -69,6 +72,14 @@ struct omap_mmc_platform_data {
 
 	u64 dma_mask;
 
+	/* omap_device function pointers */
+	int (*device_enable)(struct platform_device *pdev);
+	int (*device_shutdown)(struct platform_device *pdev);
+	int (*device_idle)(struct platform_device *pdev);
+
+	/* integration attributes from the omap_hwmod layer */
+	struct mmc_dev_attr *dev_attr;
+
 	struct omap_mmc_slot_data {
 
 		/* 4 wire signaling is optional, and is used for SD/SDIO/HSMMC;
drivers/mmc/host/omap_hsmmc.c +43 -56

199 lines not on this page · raw message