omap_device implementation, and HSMMC example
Subsystems (6)
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
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.
--- 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
@@ -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
PATCH 2/3 OMAP: MMC (core): split device registration by OMAP variant
In reply to Paul WalmsleySplit 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
@@ -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
PATCH 3/3 OMAP2/3 MMC: initial conversion to omap_device
In reply to Paul WalmsleyConvert 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
@@ -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 16void __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
@@ -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
@@ -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