Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 02/30] video/omap: fix dependencies
From: Tomi Valkeinen @ 2011-10-03  6:53 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1317566760-25681-3-git-send-email-arnd@arndb.de>

Hi Arnd,

On Sun, 2011-10-02 at 16:45 +0200, Arnd Bergmann wrote:
> The lcd_2430sdp and lcd_ldp drivers depend on TWL4030, which is not
> well expressed in the Kconfig. Create new configuration options for
> these in order to describe the dependencies correctly.
> 
> In some cases, the driver cannot be a loadable module, so better
> force it to be built-in.
> 
> While we're at it, simplify the Makefile syntax.
> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> Cc: Tomi Valkeinen <tomi.valkeinen@ti.com>
> ---
>  drivers/video/omap/Kconfig  |   41 +++++++++++++++++++++++++---
>  drivers/video/omap/Makefile |   64 ++++++++++++++++++++-----------------------
>  2 files changed, 67 insertions(+), 38 deletions(-)

I have ported lcd_2430sdp and lcd_ldp drivers (and also other OMAP2/3
panel drivers, except N800) to the newer omapdss driver
(drivers/video/omap2), and the code is in my for-next branch
(git://gitorious.org/linux-omap-dss2/linux.git for-next).

I have also worked on removing OMAP2/3 support from the old omapfb
driver, thus making it OMAP1 fb driver. This code is not yet ready, and
won't make it in the next merge window.

Your patch will conflict with both of those changes. Is it ok for you to
drop this patch, and I'll make a new one on top of my changes to clean
up the Makefile in a similar way than you did? The new patch wouldn't
make it in the next merge window, though, but I don't think this patch
is fixing any bigger bug, so perhaps it's not so urgent.

 Tomi

^ permalink raw reply

* [PATCH 03/30] video/omap: fix build dependencies
From: Tomi Valkeinen @ 2011-10-03  6:59 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1317566760-25681-4-git-send-email-arnd@arndb.de>

Hi Arnd,

On Sun, 2011-10-02 at 16:45 +0200, Arnd Bergmann wrote:
> Four of the LCD panel drivers depend on the backlight class,
> so add the dependency in Kconfig.
> Selecting the BACKLIGHT_CLASS_DEVICE symbol does not generally
> work since it has other dependencies.
> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> Cc: Tomi Valkeinen <tomi.valkeinen@ti.com>

This looks ok to me. If it's fine to you, I'll queue this patch in my
DSS tree to prevent possible conflicts.

 Tomi

^ permalink raw reply

* [PATCH 1/4] mmc: mmci: Bugfix in pio read for small packets
From: Stefan Nilsson XK @ 2011-10-03  7:08 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20111001160937.GF11710@n2100.arm.linux.org.uk>

Hi Russel,

On 10/01/2011 06:09 PM, Russell King - ARM Linux wrote:
> Does this even work?  From the MMCI spec, I see no way for the MMCI
> peripheral to know the size of the read/write on the APB bus.
>
> The APB bus signals the MMCI uses are:
>
> PCLK - APB bus clock
> PRESETn - APB bus reset
> PADDR[11:2] - APB bus address
> PSEL - APB bus peripheral select
> PENABLE - APB bus enable
> PWRITE - APB bus write signal
> PWDATA[31:0] - APB bus write data
> PRDATA[31:0] - APB bus read data
>
> As you can see, nothing in that set indicates whether it's an 8-bit,
> 16-bit or 32-bit access.

> Moreover, if you read the MMCIFifoCnt register writeup:
>
>    The MMCIFifoCnt register contains the remaining number of words to be
>    written to or read from the FIFO. The FIFO counter loads the value
>    from the data length register (see Data length register, MMCIDataLength
>    on page 3-11) when the Enable bit is set in the data control register.
>    If the data length is not word aligned (multiple of 4), the remaining
>    1 to 3 bytes are regarded as a word.
>
> This suggests that we should be reading a 32-bit word and then storing
> the relevant bytes from it.

Hmm, that is true. I will try to rework the patch to skip the case and 
only do 32 bit reads. We do however need a patch since the current 
"count" calculation is wrong (more info below). But it does in fact work.

> The other thing which concerns me is that the MMCI (ARM Ltd one at least)
> only supports power-of-two block sizes.  So requesting a transfer of a
> single block with a block size of 3 bytes is not supported by the ARM Ltd
> MMCI.  (The way you end up with 1 to 3 bytes being received with ARM's
> MMCI is if you're using a streaming transfer.)

This is true for the standard ARM block. We have however done some 
modifications of the standard block and added support for SDIO which 
also implies streaming transfers which can be non power of 2. So with 
the current implementation:

	readsl(base + MMCIFIFO, ptr, count >> 2);

when we get a request to read 3, 2 or 1 bytes (which our WLAN driver 
actually requests from time to time), this will result in reading 0 
words which is not correct. This was the original problem, but I might 
have "overdone" the solution a bit. I will upload a new patch which 
solves the original problem in a better way.

> The last thing I don't like about this patch is that this code is in a
> really hot path - one which is absolutely critical for things to work -
> and the need for the condition to be dealt with is only at the end of a
> transfer, not each time the FIFO needs emptying.
>
> Bear in mind that there are platforms with the ARM MMCI which must read
> the data within a certain time or suffer overruns, and which have either
> totally broken and useless DMA or no DMA capability at all (which are
> the only platforms I have with a MMCI on.)

I will keep this in mind. We are fortunately blessed with a working DMA 
in our platform, but for small SDIO transfers there is no point in 
setting up a DMA job which is when we fall back to PIO mode.

Best Regards

Stefan Nilsson

^ permalink raw reply

* [PATCH] clocksource: fixup ux500 build problems
From: Linus Walleij @ 2011-10-03  7:30 UTC (permalink / raw)
  To: linux-arm-kernel

Based on a patch from Arnd Bergmann this fixes up the build
problem of assigning a non-existing global when the ux500 PRCMU
timer is not linked in by passing its base address to the init
function. We also add a missing <linux/errno.h> inclusion and
staticize the dummy function.

Cc: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
 arch/arm/mach-ux500/timer.c               |    9 ++++++---
 drivers/clocksource/clksrc-dbx500-prcmu.c |    6 ++++--
 include/linux/clksrc-dbx500-prcmu.h       |    6 ++----
 3 files changed, 12 insertions(+), 9 deletions(-)

diff --git a/arch/arm/mach-ux500/timer.c b/arch/arm/mach-ux500/timer.c
index 08c55a5..aea467d 100644
--- a/arch/arm/mach-ux500/timer.c
+++ b/arch/arm/mach-ux500/timer.c
@@ -5,6 +5,7 @@
  * Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson
  */
 #include <linux/io.h>
+#include <linux/errno.h>
 #include <linux/clksrc-dbx500-prcmu.h>

 #include <asm/localtimer.h>
@@ -16,18 +17,20 @@

 static void __init ux500_timer_init(void)
 {
+       void __iomem *prcmu_timer_base;
+
        if (cpu_is_u5500()) {
 #ifdef CONFIG_LOCAL_TIMERS
                twd_base =3D __io_address(U5500_TWD_BASE);
 #endif
                mtu_base =3D __io_address(U5500_MTU0_BASE);
-               clksrc_dbx500_timer_base =3D
__io_address(U5500_PRCMU_TIMER_3_BASE);
+               prcmu_timer_base =3D __io_address(U5500_PRCMU_TIMER_3_BASE)=
;
        } else if (cpu_is_u8500()) {
 #ifdef CONFIG_LOCAL_TIMERS
                twd_base =3D __io_address(U8500_TWD_BASE);
 #endif
                mtu_base =3D __io_address(U8500_MTU0_BASE);
-               clksrc_dbx500_timer_base =3D
__io_address(U8500_PRCMU_TIMER_4_BASE);
+               prcmu_timer_base =3D __io_address(U8500_PRCMU_TIMER_4_BASE)=
;
        } else {
                ux500_unknown_soc();
        }
@@ -50,7 +53,7 @@ static void __init ux500_timer_init(void)
         */

        nmdk_timer_init();
-       clksrc_dbx500_prcmu_init();
+       clksrc_dbx500_prcmu_init(prcmu_timer_base);
 }

 static void ux500_timer_reset(void)
diff --git a/drivers/clocksource/clksrc-dbx500-prcmu.c
b/drivers/clocksource/clksrc-dbx500-prcmu.c
index 0ac5093..59feefe 100644
--- a/drivers/clocksource/clksrc-dbx500-prcmu.c
+++ b/drivers/clocksource/clksrc-dbx500-prcmu.c
@@ -31,7 +31,7 @@

 #define SCHED_CLOCK_MIN_WRAP 131072 /* 2^32 / 32768 */

-void __iomem *clksrc_dbx500_timer_base;
+static void __iomem *clksrc_dbx500_timer_base;

 static cycle_t clksrc_dbx500_prcmu_read(struct clocksource *cs)
 {
@@ -79,8 +79,10 @@ static void notrace
clksrc_dbx500_prcmu_update_sched_clock(void)
 }
 #endif

-void __init clksrc_dbx500_prcmu_init(void)
+void __init clksrc_dbx500_prcmu_init(void __iomem *base)
 {
+       clksrc_dbx500_timer_base =3D base;
+
        /*
         * The A9 sub system expects the timer to be configured as
         * a continous looping timer.
diff --git a/include/linux/clksrc-dbx500-prcmu.h
b/include/linux/clksrc-dbx500-prcmu.h
index d1e9504..4fb8119 100644
--- a/include/linux/clksrc-dbx500-prcmu.h
+++ b/include/linux/clksrc-dbx500-prcmu.h
@@ -11,12 +11,10 @@
 #include <linux/init.h>
 #include <linux/io.h>

-extern void __iomem *clksrc_dbx500_timer_base;
-
 #ifdef CONFIG_CLKSRC_DBX500_PRCMU
-void __init clksrc_dbx500_prcmu_init(void);
+void __init clksrc_dbx500_prcmu_init(void __iomem *base);
 #else
-void __init clksrc_dbx500_prcmu_init(void) {}
+static inline void __init clksrc_dbx500_prcmu_init(void __iomem *base) {}
 #endif

 #endif
--=20
1.7.3.2

I will send a new pull request separately.

Thanks!
Linus Walleij

^ permalink raw reply related

* [PATCH 4/4] mmc: mmci: Fix incorrect handling of HW flow control for SDIO
From: Stefan Nilsson XK @ 2011-10-03  7:31 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20111001161248.GG11710@n2100.arm.linux.org.uk>

Hi Russel,

On 10/01/2011 06:12 PM, Russell King - ARM Linux wrote:
> Shouldn't this also re-enable the ST hardware flow control for non-SDIO
> cards?

I do not think that is needed. Hardware flow control is turned on per 
default for all cards thanks to the .clkreg member of the variant struct:

	mmci_set_clkreg():
		clk |= variant->clkreg_enable;
where
	static struct variant_data variant_ux500v2 = {
		.clkreg_enable          = MCI_ST_UX500_HWFCEN,

This means that HWFC will be on for all cards. This patch only disables 
it for SDIO cards (thanks to the mmc_card_sdio()-check) during 
problematic transfers (HW peculiarity), and then re-enables it again for 
SDIO cards during "normal" transfers. So the HWFC state for non-SDIO 
cards should not be touched I think.

Best Regards

Stefan Nilsson

^ permalink raw reply

* [PATCH v2] ARM: EXYNOS4: Configure MAX8997 PMIC for Origen
From: Inderpal Singh @ 2011-10-03  7:36 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <005501cc817c$535eeec0$fa1ccc40$%kim@samsung.com>

Hi Kukjin,

Thanks for applying.
I would like to use inderpal.singh at linaro.org
Have updated my .gitconfig accordingly as well.

Thanks,
Inder

On 3 October 2011 08:57, Kukjin Kim <kgene.kim@samsung.com> wrote:
> Kukjin Kim wrote:
>>
>> Inderpal Singh wrote:
>> >
>> > From: Inderpal Singh <inderpal.s@samsung.com>
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ^^^^^^^^^^^
>> >
>> > Configure MAX8997 PMIC and provide platform specific data
>> > for origen.
>> >
>> > Signed-off-by: Inderpal Singh <inderpal.singh@linaro.org>
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?^^^^^^^^^^
>
> Hi Inderpal,
>
> You need to change your e-mail address of author or sign. Basically they
> should be same. Which one do you want to use?
> Then you should make sure your .gitconfig has same e-mail address......
>
> Thanks.
>
> Best regards,
> Kgene.
> --
> Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
> SW Solution Development Team, Samsung Electronics Co., Ltd.
>
>

^ permalink raw reply

* [GIT PULL] ux500-timers
From: Linus Walleij @ 2011-10-03  7:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1422315.r6YLuIojzy@wuerfel>

On Sat, Oct 1, 2011 at 6:00 PM, Arnd Bergmann <arnd@arndb.de> wrote:

> It caused a few build regressions:
>
> - missing include of errno.h
> - clksrc_dbx500_prcmu_init stub needs to be static inline, or it causes a
> ?link failure.

Sorry about this crap I'll be looking closer next time :-(

> - clksrc_dbx500_timer_base may be initialized when it's not actually linked in
>
> For the last one, I think it would actually be best to make the timer
> a platform_device and pass the address in platform_data or device tree
> property, or alternatively make it an argument to clksrc_dbx500_prcmu_init
> and make the variable static.

I chose the latter approach.

> Please send a new pull request with these things fixed, either with
> patches on top or replacing the original ones, whichever you prefer.

I have applied a hacked version of your patch like this:

^ permalink raw reply

* [GIT PULL] ux500-timers
From: Linus Walleij @ 2011-10-03  7:41 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CACRpkdbCZwSdXzqvPCrGagaikc53xLyDTQaZMRtuyqo9vw=Yng@mail.gmail.com>

Hi Arnd,

could you please pull the updated ux500 timer branch into the arm-soc
tree?

The following changes since commit d93dc5c4478c1fd5de85a3e8aece9aad7bbae044:

  Linux 3.1-rc7 (2011-09-21 16:58:15 -0700)

are available in the git repository at:
   git://git.linaro.org/people/triad/linux-stericsson.git ux500-nomadik-timers

Jonas Aaberg (4):
      ARM: ux500: Move timer code to separate file
      ARM: plat-nomadik: timer: Add support for periodic timers
      ARM: plat-nomadik: timer: Export reset functions
      ARM: ux500: Reprogram timers upon resume

Linus Walleij (1):
      clocksource: fixup ux500 build problems

Mattias Wallin (3):
      ARM: plat-nomadik: MTU sched_clock as an option
      clocksource: add DBX500 PRCMU Timer support
      ARM: ux500: add support for clocksource DBX500 PRCMU

 arch/arm/mach-ux500/Makefile                   |    2 +-
 arch/arm/mach-ux500/cpu.c                      |   29 +-----
 arch/arm/mach-ux500/include/mach/db5500-regs.h |    2 +
 arch/arm/mach-ux500/include/mach/db8500-regs.h |    3 +
 arch/arm/mach-ux500/timer.c                    |   68 ++++++++++++
 arch/arm/plat-nomadik/Kconfig                  |    8 ++-
 arch/arm/plat-nomadik/include/plat/mtu.h       |   47 +--------
 arch/arm/plat-nomadik/timer.c                  |  138 ++++++++++++++++++------
 drivers/clocksource/Kconfig                    |   15 +++
 drivers/clocksource/Makefile                   |    1 +
 drivers/clocksource/clksrc-dbx500-prcmu.c      |  106 ++++++++++++++++++
 include/linux/clksrc-dbx500-prcmu.h            |   20 ++++
 12 files changed, 333 insertions(+), 106 deletions(-)
 create mode 100644 arch/arm/mach-ux500/timer.c
 create mode 100644 drivers/clocksource/clksrc-dbx500-prcmu.c
 create mode 100644 include/linux/clksrc-dbx500-prcmu.h

^ permalink raw reply

* [PATCH V8 0/4] cpuidle: Global registration of idle states with per-cpu statistics
From: Deepthi Dharwar @ 2011-10-03  7:42 UTC (permalink / raw)
  To: linux-arm-kernel

Version 6 of this patch series dated 22nd Sept 2011 was 
Acked-by: Arjan van de Ven <arjan@linux.intel.com>
Acked-by: Kevin Hilman <khilman@ti.com> for OMAP specific parts.
Reviewed-by: Kevin Hilman <khilman@ti.com>
Tested-by: Jean Pihet <j-pihet@ti.com>

Hi Len, 
Can you please queue this series for the next mainline merge window by merging
it into your development tree and also linux-next for further testing.

I also tested it by applying these patches on your ACPI tree hosted @github.

Thanks
-Deepthi

--

The following patch series implements global registration of cpuidle
states, and also has the necessary data structure changes to
accommodate the per-cpu writable members of the cpuidle_states
structure.

This patch series had been in discussion earlier and
following are the links to the previous discussions.

v7 --> https://lkml.org/lkml/2011/9/27/74 
v6 --> https://lkml.org/lkml/2011/9/22/58
v5 --> https://lkml.org/lkml/2011/6/6/259
v4 --> https://lkml.org/lkml/2011/4/28/312
v3 --> https://lkml.org/lkml/2011/2/8/73
v2 --> https://lkml.org/lkml/2011/1/13/98
v1 --> https://lkml.org/lkml/2011/3/22/161

Changes from previous version (V7):

   1. Rebased and tested it on 3.1-rc8

   2. As suggested by Kevin in V7, Signature of Jean
      was moved from signed-off tag to tested-by.
    
Tests done:

    1. Compile tested for ARM using the following configs: da8xx_omapl_defconfig,
    exynos4_defconfig, kirkwood_defconfig, omap2plus_defconfig, 
    at91rm9200_defconfig
      
    2. Boot tested on x86 nehalem with multiple C-states for both intel_idle
    and acpi_idle drivers.

    3. Boot tested on T60p thinkpad that has T2600 cpu with multiple C-states. 
    Also tested the case when there is dynamic changes in C-states 
    AC <-> Battery Power switch.

Brief description of the patches:

Core change in this series is to split the cpuidle_device structure 
into two parts, i.e  global and per-cpu basis. 

The per-cpu pieces are mostly generic statistics that can be independent 
of current running driver. As a result of these changes, there is single 
copy of cpuidle_states structure and single registration done by one 
cpu. The low level driver is free to set per-cpu driver data on
each cpu if needed using the cpuidle_set_statedata() as the case
today. Only in very rare cases asymmetric C-states exist which can be 
handled within the cpuidle driver. Most architectures do not have 
asymmetric C-states.

First two patches in the series facilitate splitting of cpuidle_states
and cpuidle_device structure and next two patches do the actual split,
change the API's and make existing code follow the changed API.

[1/4] - Move the idle residency accounting part from cpuidle.c to
the respective low level drivers, so that the accounting can
be accurately maintained if the driver decides to demote the
chosen (suggested) by the governor.

[2/4] - removes the cpuidle_device()->prepare API since is is not
widely used and the only use case was to allow software
demotion using CPUIDLE_FLAG_IGNORE flag.  Both these
functions can be absorbed within the cpuidle back-end
driver ad hence deprecating the prepare routine and the
CPUIDLE_FLAG_IGNORE flag.

    - Ref: https://lkml.org/lkml/2011/3/25/52

[3/4] - Splits the usage statistics (read/write) part out of
cpuidle_state structure, so that the states can become read
only and hence made global.

[4/4] - Most APIs will now need to pass pointer to both global
cpuidle_driver and per-cpu cpuidle_device structure.

 arch/arm/mach-at91/cpuidle.c          |   41 +++--
 arch/arm/mach-davinci/cpuidle.c       |   51 ++++---
 arch/arm/mach-exynos4/cpuidle.c       |   30 ++--
 arch/arm/mach-kirkwood/cpuidle.c      |   42 +++---
 arch/arm/mach-omap2/cpuidle34xx.c     |  133 +++++++++++------
 arch/sh/kernel/cpu/shmobile/cpuidle.c |   28 ++--
 drivers/acpi/processor_driver.c       |   20 ---
 drivers/acpi/processor_idle.c         |  251 +++++++++++++++++++++++++++------
 drivers/cpuidle/cpuidle.c             |   86 ++++-------
 drivers/cpuidle/driver.c              |   25 +++
 drivers/cpuidle/governors/ladder.c    |   41 ++++-
 drivers/cpuidle/governors/menu.c      |   29 ++--
 drivers/cpuidle/sysfs.c               |   22 ++-
 drivers/idle/intel_idle.c             |  130 +++++++++++++----
 include/acpi/processor.h              |    1 
 include/linux/cpuidle.h               |   52 ++++---
 16 files changed, 650 insertions(+), 332 deletions(-)


-- 

-Deepthi

^ permalink raw reply

* [PATCH V8 1/4] cpuidle: Move dev->last_residency update to driver enter routine; remove dev->last_state
From: Deepthi Dharwar @ 2011-10-03  7:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20111003074147.21968.86106.stgit@localhost6.localdomain6>

Cpuidle governor only suggests the state to enter using the
governor->select() interface, but allows the low level driver to
override the recommended state. The actual entered state
may be different because of software or hardware demotion. Software
demotion is done by the back-end cpuidle driver and can be accounted
correctly. Current cpuidle code uses last_state field to capture the
actual state entered and based on that updates the statistics for the
state entered.

Ideally the driver enter routine should update the counters,
and it should return the state actually entered rather than the time
spent there. The generic cpuidle code should simply handle where
the counters live in the sysfs namespace, not updating the counters.

Reference:
https://lkml.org/lkml/2011/3/25/52

Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
Signed-off-by: Trinabh Gupta <g.trinabh@gmail.com>
Tested-by: Jean Pihet <j-pihet@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
Acked-by: Arjan van de Ven <arjan@linux.intel.com>
Acked-by: Kevin Hilman <khilman@ti.com>
---
 arch/arm/mach-at91/cpuidle.c          |   10 +++-
 arch/arm/mach-davinci/cpuidle.c       |    9 +++-
 arch/arm/mach-exynos4/cpuidle.c       |    7 ++-
 arch/arm/mach-kirkwood/cpuidle.c      |   12 ++++-
 arch/arm/mach-omap2/cpuidle34xx.c     |   67 +++++++++++++++++------------
 arch/sh/kernel/cpu/shmobile/cpuidle.c |   12 +++--
 drivers/acpi/processor_idle.c         |   75 ++++++++++++++++++++++-----------
 drivers/cpuidle/cpuidle.c             |   32 +++++++-------
 drivers/cpuidle/governors/ladder.c    |   13 ++++++
 drivers/cpuidle/governors/menu.c      |    7 ++-
 drivers/idle/intel_idle.c             |   12 ++++-
 include/linux/cpuidle.h               |    7 +--
 12 files changed, 164 insertions(+), 99 deletions(-)

diff --git a/arch/arm/mach-at91/cpuidle.c b/arch/arm/mach-at91/cpuidle.c
index 1cfeac1..4696a0d 100644
--- a/arch/arm/mach-at91/cpuidle.c
+++ b/arch/arm/mach-at91/cpuidle.c
@@ -33,7 +33,7 @@ static struct cpuidle_driver at91_idle_driver = {
 
 /* Actual code that puts the SoC in different idle states */
 static int at91_enter_idle(struct cpuidle_device *dev,
-			       struct cpuidle_state *state)
+			       int index)
 {
 	struct timeval before, after;
 	int idle_time;
@@ -41,10 +41,10 @@ static int at91_enter_idle(struct cpuidle_device *dev,
 
 	local_irq_disable();
 	do_gettimeofday(&before);
-	if (state == &dev->states[0])
+	if (index == 0)
 		/* Wait for interrupt state */
 		cpu_do_idle();
-	else if (state == &dev->states[1]) {
+	else if (index == 1) {
 		asm("b 1f; .align 5; 1:");
 		asm("mcr p15, 0, r0, c7, c10, 4");	/* drain write buffer */
 		saved_lpr = sdram_selfrefresh_enable();
@@ -55,7 +55,9 @@ static int at91_enter_idle(struct cpuidle_device *dev,
 	local_irq_enable();
 	idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
 			(after.tv_usec - before.tv_usec);
-	return idle_time;
+
+	dev->last_residency = idle_time;
+	return index;
 }
 
 /* Initialize CPU idle by registering the idle states */
diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c
index bd59f31..ca8582a 100644
--- a/arch/arm/mach-davinci/cpuidle.c
+++ b/arch/arm/mach-davinci/cpuidle.c
@@ -78,9 +78,9 @@ static struct davinci_ops davinci_states[DAVINCI_CPUIDLE_MAX_STATES] = {
 
 /* Actual code that puts the SoC in different idle states */
 static int davinci_enter_idle(struct cpuidle_device *dev,
-						struct cpuidle_state *state)
+						int index)
 {
-	struct davinci_ops *ops = cpuidle_get_statedata(state);
+	struct davinci_ops *ops = cpuidle_get_statedata(&dev->states[index]);
 	struct timeval before, after;
 	int idle_time;
 
@@ -98,7 +98,10 @@ static int davinci_enter_idle(struct cpuidle_device *dev,
 	local_irq_enable();
 	idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
 			(after.tv_usec - before.tv_usec);
-	return idle_time;
+
+	dev->last_residency = idle_time;
+
+	return index;
 }
 
 static int __init davinci_cpuidle_probe(struct platform_device *pdev)
diff --git a/arch/arm/mach-exynos4/cpuidle.c b/arch/arm/mach-exynos4/cpuidle.c
index bf7e96f..ea026e7 100644
--- a/arch/arm/mach-exynos4/cpuidle.c
+++ b/arch/arm/mach-exynos4/cpuidle.c
@@ -16,7 +16,7 @@
 #include <asm/proc-fns.h>
 
 static int exynos4_enter_idle(struct cpuidle_device *dev,
-			      struct cpuidle_state *state);
+			      int index);
 
 static struct cpuidle_state exynos4_cpuidle_set[] = {
 	[0] = {
@@ -37,7 +37,7 @@ static struct cpuidle_driver exynos4_idle_driver = {
 };
 
 static int exynos4_enter_idle(struct cpuidle_device *dev,
-			      struct cpuidle_state *state)
+			      int index)
 {
 	struct timeval before, after;
 	int idle_time;
@@ -52,7 +52,8 @@ static int exynos4_enter_idle(struct cpuidle_device *dev,
 	idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
 		    (after.tv_usec - before.tv_usec);
 
-	return idle_time;
+	dev->last_residency = idle_time;
+	return index;
 }
 
 static int __init exynos4_init_cpuidle(void)
diff --git a/arch/arm/mach-kirkwood/cpuidle.c b/arch/arm/mach-kirkwood/cpuidle.c
index f68d33f..358dd80 100644
--- a/arch/arm/mach-kirkwood/cpuidle.c
+++ b/arch/arm/mach-kirkwood/cpuidle.c
@@ -32,17 +32,17 @@ static DEFINE_PER_CPU(struct cpuidle_device, kirkwood_cpuidle_device);
 
 /* Actual code that puts the SoC in different idle states */
 static int kirkwood_enter_idle(struct cpuidle_device *dev,
-			       struct cpuidle_state *state)
+			       int index)
 {
 	struct timeval before, after;
 	int idle_time;
 
 	local_irq_disable();
 	do_gettimeofday(&before);
-	if (state == &dev->states[0])
+	if (index == 0)
 		/* Wait for interrupt state */
 		cpu_do_idle();
-	else if (state == &dev->states[1]) {
+	else if (index == 1) {
 		/*
 		 * Following write will put DDR in self refresh.
 		 * Note that we have 256 cycles before DDR puts it
@@ -57,7 +57,11 @@ static int kirkwood_enter_idle(struct cpuidle_device *dev,
 	local_irq_enable();
 	idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
 			(after.tv_usec - before.tv_usec);
-	return idle_time;
+
+	/* Update last residency */
+	dev->last_residency = idle_time;
+
+	return index;
 }
 
 /* Initialize CPU idle by registering the idle states */
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index 4bf6e6e..58425c7 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -88,17 +88,19 @@ static int _cpuidle_deny_idle(struct powerdomain *pwrdm,
 /**
  * omap3_enter_idle - Programs OMAP3 to enter the specified state
  * @dev: cpuidle device
- * @state: The target state to be programmed
+ * @index: the index of state to be entered
  *
  * Called from the CPUidle framework to program the device to the
  * specified target state selected by the governor.
  */
 static int omap3_enter_idle(struct cpuidle_device *dev,
-			struct cpuidle_state *state)
+				int index)
 {
-	struct omap3_idle_statedata *cx = cpuidle_get_statedata(state);
+	struct omap3_idle_statedata *cx =
+			cpuidle_get_statedata(&dev->states[index]);
 	struct timespec ts_preidle, ts_postidle, ts_idle;
 	u32 mpu_state = cx->mpu_state, core_state = cx->core_state;
+	int idle_time;
 
 	/* Used to keep track of the total time in idle */
 	getnstimeofday(&ts_preidle);
@@ -113,7 +115,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
 		goto return_sleep_time;
 
 	/* Deny idle for C1 */
-	if (state == &dev->states[0]) {
+	if (index == 0) {
 		pwrdm_for_each_clkdm(mpu_pd, _cpuidle_deny_idle);
 		pwrdm_for_each_clkdm(core_pd, _cpuidle_deny_idle);
 	}
@@ -122,7 +124,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
 	omap_sram_idle();
 
 	/* Re-allow idle for C1 */
-	if (state == &dev->states[0]) {
+	if (index == 0) {
 		pwrdm_for_each_clkdm(mpu_pd, _cpuidle_allow_idle);
 		pwrdm_for_each_clkdm(core_pd, _cpuidle_allow_idle);
 	}
@@ -134,28 +136,35 @@ return_sleep_time:
 	local_irq_enable();
 	local_fiq_enable();
 
-	return ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * USEC_PER_SEC;
+	idle_time = ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * \
+								USEC_PER_SEC;
+
+	/* Update cpuidle counters */
+	dev->last_residency = idle_time;
+
+	return index;
 }
 
 /**
  * next_valid_state - Find next valid C-state
  * @dev: cpuidle device
- * @state: Currently selected C-state
+ * @index: Index of currently selected c-state
  *
- * If the current state is valid, it is returned back to the caller.
- * Else, this function searches for a lower c-state which is still
- * valid.
+ * If the state corresponding to index is valid, index is returned back
+ * to the caller. Else, this function searches for a lower c-state which is
+ * still valid (as defined in omap3_power_states[]) and returns its index.
  *
  * A state is valid if the 'valid' field is enabled and
  * if it satisfies the enable_off_mode condition.
  */
-static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
-					      struct cpuidle_state *curr)
+static int next_valid_state(struct cpuidle_device *dev,
+				int index)
 {
-	struct cpuidle_state *next = NULL;
+	struct cpuidle_state *curr = &dev->states[index];
 	struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr);
 	u32 mpu_deepest_state = PWRDM_POWER_RET;
 	u32 core_deepest_state = PWRDM_POWER_RET;
+	int next_index = -1;
 
 	if (enable_off_mode) {
 		mpu_deepest_state = PWRDM_POWER_OFF;
@@ -172,20 +181,20 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
 	if ((cx->valid) &&
 	    (cx->mpu_state >= mpu_deepest_state) &&
 	    (cx->core_state >= core_deepest_state)) {
-		return curr;
+		return index;
 	} else {
 		int idx = OMAP3_NUM_STATES - 1;
 
 		/* Reach the current state starting at highest C-state */
 		for (; idx >= 0; idx--) {
 			if (&dev->states[idx] == curr) {
-				next = &dev->states[idx];
+				next_index = idx;
 				break;
 			}
 		}
 
 		/* Should never hit this condition */
-		WARN_ON(next == NULL);
+		WARN_ON(next_index == -1);
 
 		/*
 		 * Drop to next valid state.
@@ -197,37 +206,39 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
 			if ((cx->valid) &&
 			    (cx->mpu_state >= mpu_deepest_state) &&
 			    (cx->core_state >= core_deepest_state)) {
-				next = &dev->states[idx];
+				next_index = idx;
 				break;
 			}
 		}
 		/*
 		 * C1 is always valid.
-		 * So, no need to check for 'next==NULL' outside this loop.
+		 * So, no need to check for 'next_index == -1' outside
+		 * this loop.
 		 */
 	}
 
-	return next;
+	return next_index;
 }
 
 /**
  * omap3_enter_idle_bm - Checks for any bus activity
  * @dev: cpuidle device
- * @state: The target state to be programmed
+ * @index: array index of target state to be programmed
  *
  * This function checks for any pending activity and then programs
  * the device to the specified or a safer state.
  */
 static int omap3_enter_idle_bm(struct cpuidle_device *dev,
-			       struct cpuidle_state *state)
+			       int index)
 {
-	struct cpuidle_state *new_state;
+	struct cpuidle_state *state = &dev->states[index];
+	int new_state_idx;
 	u32 core_next_state, per_next_state = 0, per_saved_state = 0, cam_state;
 	struct omap3_idle_statedata *cx;
 	int ret;
 
 	if (!omap3_can_sleep()) {
-		new_state = dev->safe_state;
+		new_state_idx = dev->safe_state_index;
 		goto select_state;
 	}
 
@@ -237,7 +248,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
 	 */
 	cam_state = pwrdm_read_pwrst(cam_pd);
 	if (cam_state == PWRDM_POWER_ON) {
-		new_state = dev->safe_state;
+		new_state_idx = dev->safe_state_index;
 		goto select_state;
 	}
 
@@ -264,11 +275,10 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
 	if (per_next_state != per_saved_state)
 		pwrdm_set_next_pwrst(per_pd, per_next_state);
 
-	new_state = next_valid_state(dev, state);
+	new_state_idx = next_valid_state(dev, index);
 
 select_state:
-	dev->last_state = new_state;
-	ret = omap3_enter_idle(dev, new_state);
+	ret = omap3_enter_idle(dev, new_state_idx);
 
 	/* Restore original PER state if it was modified */
 	if (per_next_state != per_saved_state)
@@ -339,11 +349,12 @@ int __init omap3_idle_init(void)
 
 	cpuidle_register_driver(&omap3_idle_driver);
 	dev = &per_cpu(omap3_idle_dev, smp_processor_id());
+	dev->safe_state_index = -1;
 
 	/* C1 . MPU WFI + Core active */
 	cx = _fill_cstate(dev, 0, "MPU ON + CORE ON");
 	(&dev->states[0])->enter = omap3_enter_idle;
-	dev->safe_state = &dev->states[0];
+	dev->safe_state_index = 0;
 	cx->valid = 1;	/* C1 is always valid */
 	cx->mpu_state = PWRDM_POWER_ON;
 	cx->core_state = PWRDM_POWER_ON;
diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c
index e4469e72..7be50d4c 100644
--- a/arch/sh/kernel/cpu/shmobile/cpuidle.c
+++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c
@@ -25,11 +25,11 @@ static unsigned long cpuidle_mode[] = {
 };
 
 static int cpuidle_sleep_enter(struct cpuidle_device *dev,
-			       struct cpuidle_state *state)
+				int index)
 {
 	unsigned long allowed_mode = arch_hwblk_sleep_mode();
 	ktime_t before, after;
-	int requested_state = state - &dev->states[0];
+	int requested_state = index;
 	int allowed_state;
 	int k;
 
@@ -46,11 +46,13 @@ static int cpuidle_sleep_enter(struct cpuidle_device *dev,
 	 */
 	k = min_t(int, allowed_state, requested_state);
 
-	dev->last_state = &dev->states[k];
 	before = ktime_get();
 	sh_mobile_call_standby(cpuidle_mode[k]);
 	after = ktime_get();
-	return ktime_to_ns(ktime_sub(after, before)) >> 10;
+
+	dev->last_residency = (int)ktime_to_ns(ktime_sub(after, before)) >> 10;
+
+	return k;
 }
 
 static struct cpuidle_device cpuidle_dev;
@@ -84,7 +86,7 @@ void sh_mobile_setup_cpuidle(void)
 	state->flags |= CPUIDLE_FLAG_TIME_VALID;
 	state->enter = cpuidle_sleep_enter;
 
-	dev->safe_state = state;
+	dev->safe_state_index = i-1;
 
 	if (sh_mobile_sleep_supported & SUSP_SH_SF) {
 		state = &dev->states[i++];
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 431ab11..9cd08ce 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -741,22 +741,24 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx)
 /**
  * acpi_idle_enter_c1 - enters an ACPI C1 state-type
  * @dev: the target CPU
- * @state: the state data
+ * @index: index of target state
  *
  * This is equivalent to the HALT instruction.
  */
 static int acpi_idle_enter_c1(struct cpuidle_device *dev,
-			      struct cpuidle_state *state)
+				int index)
 {
 	ktime_t  kt1, kt2;
 	s64 idle_time;
 	struct acpi_processor *pr;
+	struct cpuidle_state *state = &dev->states[index];
 	struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
 
 	pr = __this_cpu_read(processors);
+	dev->last_residency = 0;
 
 	if (unlikely(!pr))
-		return 0;
+		return -EINVAL;
 
 	local_irq_disable();
 
@@ -764,7 +766,7 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
 	if (acpi_idle_suspend) {
 		local_irq_enable();
 		cpu_relax();
-		return 0;
+		return -EINVAL;
 	}
 
 	lapic_timer_state_broadcast(pr, cx, 1);
@@ -773,37 +775,46 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
 	kt2 = ktime_get_real();
 	idle_time =  ktime_to_us(ktime_sub(kt2, kt1));
 
+	/* Update device last_residency*/
+	dev->last_residency = (int)idle_time;
+
 	local_irq_enable();
 	cx->usage++;
 	lapic_timer_state_broadcast(pr, cx, 0);
 
-	return idle_time;
+	return index;
 }
 
 /**
  * acpi_idle_enter_simple - enters an ACPI state without BM handling
  * @dev: the target CPU
- * @state: the state data
+ * @index: the index of suggested state
  */
 static int acpi_idle_enter_simple(struct cpuidle_device *dev,
-				  struct cpuidle_state *state)
+				int index)
 {
 	struct acpi_processor *pr;
+	struct cpuidle_state *state = &dev->states[index];
 	struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
 	ktime_t  kt1, kt2;
 	s64 idle_time_ns;
 	s64 idle_time;
 
 	pr = __this_cpu_read(processors);
+	dev->last_residency = 0;
 
 	if (unlikely(!pr))
-		return 0;
-
-	if (acpi_idle_suspend)
-		return(acpi_idle_enter_c1(dev, state));
+		return -EINVAL;
 
 	local_irq_disable();
 
+	if (acpi_idle_suspend) {
+		local_irq_enable();
+		cpu_relax();
+		return -EINVAL;
+	}
+
+
 	if (cx->entry_method != ACPI_CSTATE_FFH) {
 		current_thread_info()->status &= ~TS_POLLING;
 		/*
@@ -815,7 +826,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
 		if (unlikely(need_resched())) {
 			current_thread_info()->status |= TS_POLLING;
 			local_irq_enable();
-			return 0;
+			return -EINVAL;
 		}
 	}
 
@@ -837,6 +848,9 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
 	idle_time = idle_time_ns;
 	do_div(idle_time, NSEC_PER_USEC);
 
+	/* Update device last_residency*/
+	dev->last_residency = (int)idle_time;
+
 	/* Tell the scheduler how much we idled: */
 	sched_clock_idle_wakeup_event(idle_time_ns);
 
@@ -848,7 +862,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
 
 	lapic_timer_state_broadcast(pr, cx, 0);
 	cx->time += idle_time;
-	return idle_time;
+	return index;
 }
 
 static int c3_cpu_count;
@@ -857,14 +871,15 @@ static DEFINE_SPINLOCK(c3_lock);
 /**
  * acpi_idle_enter_bm - enters C3 with proper BM handling
  * @dev: the target CPU
- * @state: the state data
+ * @index: the index of suggested state
  *
  * If BM is detected, the deepest non-C3 idle state is entered instead.
  */
 static int acpi_idle_enter_bm(struct cpuidle_device *dev,
-			      struct cpuidle_state *state)
+				int index)
 {
 	struct acpi_processor *pr;
+	struct cpuidle_state *state = &dev->states[index];
 	struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
 	ktime_t  kt1, kt2;
 	s64 idle_time_ns;
@@ -872,22 +887,26 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
 
 
 	pr = __this_cpu_read(processors);
+	dev->last_residency = 0;
 
 	if (unlikely(!pr))
-		return 0;
+		return -EINVAL;
 
-	if (acpi_idle_suspend)
-		return(acpi_idle_enter_c1(dev, state));
+
+	if (acpi_idle_suspend) {
+		cpu_relax();
+		return -EINVAL;
+	}
 
 	if (!cx->bm_sts_skip && acpi_idle_bm_check()) {
-		if (dev->safe_state) {
-			dev->last_state = dev->safe_state;
-			return dev->safe_state->enter(dev, dev->safe_state);
+		if (dev->safe_state_index >= 0) {
+			return dev->states[dev->safe_state_index].enter(dev,
+						dev->safe_state_index);
 		} else {
 			local_irq_disable();
 			acpi_safe_halt();
 			local_irq_enable();
-			return 0;
+			return -EINVAL;
 		}
 	}
 
@@ -904,7 +923,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
 		if (unlikely(need_resched())) {
 			current_thread_info()->status |= TS_POLLING;
 			local_irq_enable();
-			return 0;
+			return -EINVAL;
 		}
 	}
 
@@ -954,6 +973,9 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
 	idle_time = idle_time_ns;
 	do_div(idle_time, NSEC_PER_USEC);
 
+	/* Update device last_residency*/
+	dev->last_residency = (int)idle_time;
+
 	/* Tell the scheduler how much we idled: */
 	sched_clock_idle_wakeup_event(idle_time_ns);
 
@@ -965,7 +987,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
 
 	lapic_timer_state_broadcast(pr, cx, 0);
 	cx->time += idle_time;
-	return idle_time;
+	return index;
 }
 
 struct cpuidle_driver acpi_idle_driver = {
@@ -992,6 +1014,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
 	}
 
 	dev->cpu = pr->id;
+	dev->safe_state_index = -1;
 	for (i = 0; i < CPUIDLE_STATE_MAX; i++) {
 		dev->states[i].name[0] = '\0';
 		dev->states[i].desc[0] = '\0';
@@ -1027,13 +1050,13 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
 				state->flags |= CPUIDLE_FLAG_TIME_VALID;
 
 			state->enter = acpi_idle_enter_c1;
-			dev->safe_state = state;
+			dev->safe_state_index = count;
 			break;
 
 			case ACPI_STATE_C2:
 			state->flags |= CPUIDLE_FLAG_TIME_VALID;
 			state->enter = acpi_idle_enter_simple;
-			dev->safe_state = state;
+			dev->safe_state_index = count;
 			break;
 
 			case ACPI_STATE_C3:
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index d4c5423..88bd121 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -62,7 +62,7 @@ int cpuidle_idle_call(void)
 {
 	struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
 	struct cpuidle_state *target_state;
-	int next_state;
+	int next_state, entered_state;
 
 	if (off)
 		return -ENODEV;
@@ -102,26 +102,27 @@ int cpuidle_idle_call(void)
 
 	target_state = &dev->states[next_state];
 
-	/* enter the state and update stats */
-	dev->last_state = target_state;
-
 	trace_power_start(POWER_CSTATE, next_state, dev->cpu);
 	trace_cpu_idle(next_state, dev->cpu);
 
-	dev->last_residency = target_state->enter(dev, target_state);
+	entered_state = target_state->enter(dev, next_state);
 
 	trace_power_end(dev->cpu);
 	trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu);
 
-	if (dev->last_state)
-		target_state = dev->last_state;
-
-	target_state->time += (unsigned long long)dev->last_residency;
-	target_state->usage++;
+	if (entered_state >= 0) {
+		/* Update cpuidle counters */
+		/* This can be moved to within driver enter routine
+		 * but that results in multiple copies of same code.
+		 */
+		dev->states[entered_state].time +=
+				(unsigned long long)dev->last_residency;
+		dev->states[entered_state].usage++;
+	}
 
 	/* give the governor an opportunity to reflect on the outcome */
 	if (cpuidle_curr_governor->reflect)
-		cpuidle_curr_governor->reflect(dev);
+		cpuidle_curr_governor->reflect(dev, entered_state);
 
 	return 0;
 }
@@ -172,11 +173,10 @@ void cpuidle_resume_and_unlock(void)
 EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock);
 
 #ifdef CONFIG_ARCH_HAS_CPU_RELAX
-static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st)
+static int poll_idle(struct cpuidle_device *dev, int index)
 {
 	ktime_t	t1, t2;
 	s64 diff;
-	int ret;
 
 	t1 = ktime_get();
 	local_irq_enable();
@@ -188,8 +188,9 @@ static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st)
 	if (diff > INT_MAX)
 		diff = INT_MAX;
 
-	ret = (int) diff;
-	return ret;
+	dev->last_residency = (int) diff;
+
+	return index;
 }
 
 static void poll_idle_init(struct cpuidle_device *dev)
@@ -248,7 +249,6 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
 		dev->states[i].time = 0;
 	}
 	dev->last_residency = 0;
-	dev->last_state = NULL;
 
 	smp_wmb();
 
diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c
index 12c9890..6a686a7 100644
--- a/drivers/cpuidle/governors/ladder.c
+++ b/drivers/cpuidle/governors/ladder.c
@@ -153,11 +153,24 @@ static int ladder_enable_device(struct cpuidle_device *dev)
 	return 0;
 }
 
+/**
+ * ladder_reflect - update the correct last_state_idx
+ * @dev: the CPU
+ * @index: the index of actual state entered
+ */
+static void ladder_reflect(struct cpuidle_device *dev, int index)
+{
+	struct ladder_device *ldev = &__get_cpu_var(ladder_devices);
+	if (index > 0)
+		ldev->last_state_idx = index;
+}
+
 static struct cpuidle_governor ladder_governor = {
 	.name =		"ladder",
 	.rating =	10,
 	.enable =	ladder_enable_device,
 	.select =	ladder_select_state,
+	.reflect =	ladder_reflect,
 	.owner =	THIS_MODULE,
 };
 
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index c47f3d0..e4b200c 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -310,14 +310,17 @@ static int menu_select(struct cpuidle_device *dev)
 /**
  * menu_reflect - records that data structures need update
  * @dev: the CPU
+ * @index: the index of actual entered state
  *
  * NOTE: it's important to be fast here because this operation will add to
  *       the overall exit latency.
  */
-static void menu_reflect(struct cpuidle_device *dev)
+static void menu_reflect(struct cpuidle_device *dev, int index)
 {
 	struct menu_device *data = &__get_cpu_var(menu_devices);
-	data->needs_update = 1;
+	data->last_state_idx = index;
+	if (index >= 0)
+		data->needs_update = 1;
 }
 
 /**
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index a46dddf..a1c888d 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -81,7 +81,7 @@ static unsigned int mwait_substates;
 static unsigned int lapic_timer_reliable_states = (1 << 1);	 /* Default to only C1 */
 
 static struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
-static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state);
+static int intel_idle(struct cpuidle_device *dev, int index);
 
 static struct cpuidle_state *cpuidle_state_table;
 
@@ -209,12 +209,13 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
 /**
  * intel_idle
  * @dev: cpuidle_device
- * @state: cpuidle state
+ * @index: index of cpuidle state
  *
  */
-static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state)
+static int intel_idle(struct cpuidle_device *dev, int index)
 {
 	unsigned long ecx = 1; /* break on interrupt flag */
+	struct cpuidle_state *state = &dev->states[index];
 	unsigned long eax = (unsigned long)cpuidle_get_statedata(state);
 	unsigned int cstate;
 	ktime_t kt_before, kt_after;
@@ -256,7 +257,10 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state)
 	if (!(lapic_timer_reliable_states & (1 << (cstate))))
 		clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
 
-	return usec_delta;
+	/* Update cpuidle counters */
+	dev->last_residency = (int)usec_delta;
+
+	return index;
 }
 
 static void __setup_broadcast_timer(void *arg)
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index b51629e..8da811b 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -42,7 +42,7 @@ struct cpuidle_state {
 	unsigned long long	time; /* in US */
 
 	int (*enter)	(struct cpuidle_device *dev,
-			 struct cpuidle_state *state);
+			int index);
 };
 
 /* Idle State Flags */
@@ -87,13 +87,12 @@ struct cpuidle_device {
 	int			state_count;
 	struct cpuidle_state	states[CPUIDLE_STATE_MAX];
 	struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX];
-	struct cpuidle_state	*last_state;
 
 	struct list_head 	device_list;
 	struct kobject		kobj;
 	struct completion	kobj_unregister;
 	void			*governor_data;
-	struct cpuidle_state	*safe_state;
+	int			safe_state_index;
 
 	int (*prepare)		(struct cpuidle_device *dev);
 };
@@ -169,7 +168,7 @@ struct cpuidle_governor {
 	void (*disable)		(struct cpuidle_device *dev);
 
 	int  (*select)		(struct cpuidle_device *dev);
-	void (*reflect)		(struct cpuidle_device *dev);
+	void (*reflect)		(struct cpuidle_device *dev, int index);
 
 	struct module 		*owner;
 };

^ permalink raw reply related

* [PATCH V8 2/4] cpuidle: Remove CPUIDLE_FLAG_IGNORE and dev->prepare()
From: Deepthi Dharwar @ 2011-10-03  7:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20111003074147.21968.86106.stgit@localhost6.localdomain6>

The cpuidle_device->prepare() mechanism causes updates to the
cpuidle_state[].flags, setting and clearing CPUIDLE_FLAG_IGNORE
to tell the governor not to chose a state on a per-cpu basis at
run-time. State demotion is now handled by the driver and it returns
the actual state entered. Hence, this mechanism is not required.
Also this removes per-cpu flags from cpuidle_state enabling
it to be made global.

Reference:
https://lkml.org/lkml/2011/3/25/52

Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm>
Signed-off-by: Trinabh Gupta <g.trinabh@gmail.com>
Tested-by: Jean Pihet <j-pihet@ti.com>
Acked-by: Arjan van de Ven <arjan@linux.intel.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
---
 drivers/cpuidle/cpuidle.c        |   10 ----------
 drivers/cpuidle/governors/menu.c |    2 --
 include/linux/cpuidle.h          |    3 ---
 3 files changed, 0 insertions(+), 15 deletions(-)

diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 88bd121..f66bcf9 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -83,16 +83,6 @@ int cpuidle_idle_call(void)
 	hrtimer_peek_ahead_timers();
 #endif
 
-	/*
-	 * Call the device's prepare function before calling the
-	 * governor's select function.  ->prepare gives the device's
-	 * cpuidle driver a chance to update any dynamic information
-	 * of its cpuidle states for the current idle period, e.g.
-	 * state availability, latencies, residencies, etc.
-	 */
-	if (dev->prepare)
-		dev->prepare(dev);
-
 	/* ask the governor for the next state */
 	next_state = cpuidle_curr_governor->select(dev);
 	if (need_resched()) {
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index e4b200c..af724e8 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -288,8 +288,6 @@ static int menu_select(struct cpuidle_device *dev)
 	for (i = CPUIDLE_DRIVER_STATE_START; i < dev->state_count; i++) {
 		struct cpuidle_state *s = &dev->states[i];
 
-		if (s->flags & CPUIDLE_FLAG_IGNORE)
-			continue;
 		if (s->target_residency > data->predicted_us)
 			continue;
 		if (s->exit_latency > latency_req)
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index 8da811b..c6d85cf 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -47,7 +47,6 @@ struct cpuidle_state {
 
 /* Idle State Flags */
 #define CPUIDLE_FLAG_TIME_VALID	(0x01) /* is residency time measurable? */
-#define CPUIDLE_FLAG_IGNORE	(0x100) /* ignore during this idle period */
 
 #define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000)
 
@@ -93,8 +92,6 @@ struct cpuidle_device {
 	struct completion	kobj_unregister;
 	void			*governor_data;
 	int			safe_state_index;
-
-	int (*prepare)		(struct cpuidle_device *dev);
 };
 
 DECLARE_PER_CPU(struct cpuidle_device *, cpuidle_devices);

^ permalink raw reply related

* [PATCH V8 3/4] cpuidle: Split cpuidle_state structure and move per-cpu statistics fields
From: Deepthi Dharwar @ 2011-10-03  7:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20111003074147.21968.86106.stgit@localhost6.localdomain6>

This is the first step towards global registration of cpuidle
states. The statistics used primarily by the governor are per-cpu
and have to be split from rest of the fields inside cpuidle_state,
which would be made global i.e. single copy. The driver_data field
is also per-cpu and moved.

Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
Signed-off-by: Trinabh Gupta <g.trinabh@gmail.com>
Tested-by: Jean Pihet <j-pihet@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
Acked-by: Arjan van de Ven <arjan@linux.intel.com>
Acked-by: Kevin Hilman <khilman@ti.com>
---
 arch/arm/mach-davinci/cpuidle.c   |    5 ++--
 arch/arm/mach-omap2/cpuidle34xx.c |   13 ++++++----
 drivers/acpi/processor_idle.c     |   25 ++++++++++----------
 drivers/cpuidle/cpuidle.c         |   11 +++++----
 drivers/cpuidle/sysfs.c           |   19 ++++++++++-----
 drivers/idle/intel_idle.c         |   46 +++++++++++++++++++++++++++----------
 include/linux/cpuidle.h           |   25 ++++++++++++--------
 7 files changed, 90 insertions(+), 54 deletions(-)

diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c
index ca8582a..f2d2f34 100644
--- a/arch/arm/mach-davinci/cpuidle.c
+++ b/arch/arm/mach-davinci/cpuidle.c
@@ -80,7 +80,8 @@ static struct davinci_ops davinci_states[DAVINCI_CPUIDLE_MAX_STATES] = {
 static int davinci_enter_idle(struct cpuidle_device *dev,
 						int index)
 {
-	struct davinci_ops *ops = cpuidle_get_statedata(&dev->states[index]);
+	struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
+	struct davinci_ops *ops = cpuidle_get_statedata(state_usage);
 	struct timeval before, after;
 	int idle_time;
 
@@ -142,7 +143,7 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev)
 	strcpy(device->states[1].desc, "WFI and DDR Self Refresh");
 	if (pdata->ddr2_pdown)
 		davinci_states[1].flags |= DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN;
-	cpuidle_set_statedata(&device->states[1], &davinci_states[1]);
+	cpuidle_set_statedata(&device->states_usage[1], &davinci_states[1]);
 
 	device->state_count = DAVINCI_CPUIDLE_MAX_STATES;
 
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index 58425c7..d3fce7b 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -97,7 +97,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
 				int index)
 {
 	struct omap3_idle_statedata *cx =
-			cpuidle_get_statedata(&dev->states[index]);
+			cpuidle_get_statedata(&dev->states_usage[index]);
 	struct timespec ts_preidle, ts_postidle, ts_idle;
 	u32 mpu_state = cx->mpu_state, core_state = cx->core_state;
 	int idle_time;
@@ -160,8 +160,9 @@ return_sleep_time:
 static int next_valid_state(struct cpuidle_device *dev,
 				int index)
 {
+	struct cpuidle_state_usage *curr_usage = &dev->states_usage[index];
 	struct cpuidle_state *curr = &dev->states[index];
-	struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr);
+	struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr_usage);
 	u32 mpu_deepest_state = PWRDM_POWER_RET;
 	u32 core_deepest_state = PWRDM_POWER_RET;
 	int next_index = -1;
@@ -202,7 +203,7 @@ static int next_valid_state(struct cpuidle_device *dev,
 		 */
 		idx--;
 		for (; idx >= 0; idx--) {
-			cx = cpuidle_get_statedata(&dev->states[idx]);
+			cx = cpuidle_get_statedata(&dev->states_usage[idx]);
 			if ((cx->valid) &&
 			    (cx->mpu_state >= mpu_deepest_state) &&
 			    (cx->core_state >= core_deepest_state)) {
@@ -231,7 +232,6 @@ static int next_valid_state(struct cpuidle_device *dev,
 static int omap3_enter_idle_bm(struct cpuidle_device *dev,
 			       int index)
 {
-	struct cpuidle_state *state = &dev->states[index];
 	int new_state_idx;
 	u32 core_next_state, per_next_state = 0, per_saved_state = 0, cam_state;
 	struct omap3_idle_statedata *cx;
@@ -264,7 +264,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
 	 * Prevent PER off if CORE is not in retention or off as this
 	 * would disable PER wakeups completely.
 	 */
-	cx = cpuidle_get_statedata(state);
+	cx = cpuidle_get_statedata(&dev->states_usage[index]);
 	core_next_state = cx->core_state;
 	per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd);
 	if ((per_next_state == PWRDM_POWER_OFF) &&
@@ -318,6 +318,7 @@ static inline struct omap3_idle_statedata *_fill_cstate(
 {
 	struct omap3_idle_statedata *cx = &omap3_idle_data[idx];
 	struct cpuidle_state *state = &dev->states[idx];
+	struct cpuidle_state_usage *state_usage = &dev->states_usage[idx];
 
 	state->exit_latency	= cpuidle_params_table[idx].exit_latency;
 	state->target_residency	= cpuidle_params_table[idx].target_residency;
@@ -326,7 +327,7 @@ static inline struct omap3_idle_statedata *_fill_cstate(
 	cx->valid		= cpuidle_params_table[idx].valid;
 	sprintf(state->name, "C%d", idx + 1);
 	strncpy(state->desc, descr, CPUIDLE_DESC_LEN);
-	cpuidle_set_statedata(state, cx);
+	cpuidle_set_statedata(state_usage, cx);
 
 	return cx;
 }
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 9cd08ce..b98c752 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -745,14 +745,13 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx)
  *
  * This is equivalent to the HALT instruction.
  */
-static int acpi_idle_enter_c1(struct cpuidle_device *dev,
-				int index)
+static int acpi_idle_enter_c1(struct cpuidle_device *dev, int index)
 {
 	ktime_t  kt1, kt2;
 	s64 idle_time;
 	struct acpi_processor *pr;
-	struct cpuidle_state *state = &dev->states[index];
-	struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
+	struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
+	struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage);
 
 	pr = __this_cpu_read(processors);
 	dev->last_residency = 0;
@@ -790,12 +789,11 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
  * @dev: the target CPU
  * @index: the index of suggested state
  */
-static int acpi_idle_enter_simple(struct cpuidle_device *dev,
-				int index)
+static int acpi_idle_enter_simple(struct cpuidle_device *dev, int index)
 {
 	struct acpi_processor *pr;
-	struct cpuidle_state *state = &dev->states[index];
-	struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
+	struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
+	struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage);
 	ktime_t  kt1, kt2;
 	s64 idle_time_ns;
 	s64 idle_time;
@@ -875,12 +873,11 @@ static DEFINE_SPINLOCK(c3_lock);
  *
  * If BM is detected, the deepest non-C3 idle state is entered instead.
  */
-static int acpi_idle_enter_bm(struct cpuidle_device *dev,
-				int index)
+static int acpi_idle_enter_bm(struct cpuidle_device *dev, int index)
 {
 	struct acpi_processor *pr;
-	struct cpuidle_state *state = &dev->states[index];
-	struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
+	struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
+	struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage);
 	ktime_t  kt1, kt2;
 	s64 idle_time_ns;
 	s64 idle_time;
@@ -1004,6 +1001,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
 	int i, count = CPUIDLE_DRIVER_STATE_START;
 	struct acpi_processor_cx *cx;
 	struct cpuidle_state *state;
+	struct cpuidle_state_usage *state_usage;
 	struct cpuidle_device *dev = &pr->power.dev;
 
 	if (!pr->flags.power_setup_done)
@@ -1026,6 +1024,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
 	for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) {
 		cx = &pr->power.states[i];
 		state = &dev->states[count];
+		state_usage = &dev->states_usage[count];
 
 		if (!cx->valid)
 			continue;
@@ -1036,7 +1035,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
 		    !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
 			continue;
 #endif
-		cpuidle_set_statedata(state, cx);
+		cpuidle_set_statedata(state_usage, cx);
 
 		snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i);
 		strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN);
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index f66bcf9..7127e92 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -105,9 +105,9 @@ int cpuidle_idle_call(void)
 		/* This can be moved to within driver enter routine
 		 * but that results in multiple copies of same code.
 		 */
-		dev->states[entered_state].time +=
+		dev->states_usage[entered_state].time +=
 				(unsigned long long)dev->last_residency;
-		dev->states[entered_state].usage++;
+		dev->states_usage[entered_state].usage++;
 	}
 
 	/* give the governor an opportunity to reflect on the outcome */
@@ -186,8 +186,9 @@ static int poll_idle(struct cpuidle_device *dev, int index)
 static void poll_idle_init(struct cpuidle_device *dev)
 {
 	struct cpuidle_state *state = &dev->states[0];
+	struct cpuidle_state_usage *state_usage = &dev->states_usage[0];
 
-	cpuidle_set_statedata(state, NULL);
+	cpuidle_set_statedata(state_usage, NULL);
 
 	snprintf(state->name, CPUIDLE_NAME_LEN, "POLL");
 	snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE");
@@ -235,8 +236,8 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
 		goto fail_sysfs;
 
 	for (i = 0; i < dev->state_count; i++) {
-		dev->states[i].usage = 0;
-		dev->states[i].time = 0;
+		dev->states_usage[i].usage = 0;
+		dev->states_usage[i].time = 0;
 	}
 	dev->last_residency = 0;
 
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c
index be7917ec..8a1ace1 100644
--- a/drivers/cpuidle/sysfs.c
+++ b/drivers/cpuidle/sysfs.c
@@ -216,7 +216,8 @@ static struct kobj_type ktype_cpuidle = {
 
 struct cpuidle_state_attr {
 	struct attribute attr;
-	ssize_t (*show)(struct cpuidle_state *, char *);
+	ssize_t (*show)(struct cpuidle_state *, \
+					struct cpuidle_state_usage *, char *);
 	ssize_t (*store)(struct cpuidle_state *, const char *, size_t);
 };
 
@@ -224,19 +225,22 @@ struct cpuidle_state_attr {
 static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0444, show, NULL)
 
 #define define_show_state_function(_name) \
-static ssize_t show_state_##_name(struct cpuidle_state *state, char *buf) \
+static ssize_t show_state_##_name(struct cpuidle_state *state, \
+			 struct cpuidle_state_usage *state_usage, char *buf) \
 { \
 	return sprintf(buf, "%u\n", state->_name);\
 }
 
 #define define_show_state_ull_function(_name) \
-static ssize_t show_state_##_name(struct cpuidle_state *state, char *buf) \
+static ssize_t show_state_##_name(struct cpuidle_state *state, \
+			struct cpuidle_state_usage *state_usage, char *buf) \
 { \
-	return sprintf(buf, "%llu\n", state->_name);\
+	return sprintf(buf, "%llu\n", state_usage->_name);\
 }
 
 #define define_show_state_str_function(_name) \
-static ssize_t show_state_##_name(struct cpuidle_state *state, char *buf) \
+static ssize_t show_state_##_name(struct cpuidle_state *state, \
+			struct cpuidle_state_usage *state_usage, char *buf) \
 { \
 	if (state->_name[0] == '\0')\
 		return sprintf(buf, "<null>\n");\
@@ -269,16 +273,18 @@ static struct attribute *cpuidle_state_default_attrs[] = {
 
 #define kobj_to_state_obj(k) container_of(k, struct cpuidle_state_kobj, kobj)
 #define kobj_to_state(k) (kobj_to_state_obj(k)->state)
+#define kobj_to_state_usage(k) (kobj_to_state_obj(k)->state_usage)
 #define attr_to_stateattr(a) container_of(a, struct cpuidle_state_attr, attr)
 static ssize_t cpuidle_state_show(struct kobject * kobj,
 	struct attribute * attr ,char * buf)
 {
 	int ret = -EIO;
 	struct cpuidle_state *state = kobj_to_state(kobj);
+	struct cpuidle_state_usage *state_usage = kobj_to_state_usage(kobj);
 	struct cpuidle_state_attr * cattr = attr_to_stateattr(attr);
 
 	if (cattr->show)
-		ret = cattr->show(state, buf);
+		ret = cattr->show(state, state_usage, buf);
 
 	return ret;
 }
@@ -323,6 +329,7 @@ int cpuidle_add_state_sysfs(struct cpuidle_device *device)
 		if (!kobj)
 			goto error_state;
 		kobj->state = &device->states[i];
+		kobj->state_usage = &device->states_usage[i];
 		init_completion(&kobj->kobj_unregister);
 
 		ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle, &device->kobj,
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index a1c888d..3aa8d4c 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -109,7 +109,6 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
 	{ /* MWAIT C1 */
 		.name = "C1-NHM",
 		.desc = "MWAIT 0x00",
-		.driver_data = (void *) 0x00,
 		.flags = CPUIDLE_FLAG_TIME_VALID,
 		.exit_latency = 3,
 		.target_residency = 6,
@@ -117,7 +116,6 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
 	{ /* MWAIT C2 */
 		.name = "C3-NHM",
 		.desc = "MWAIT 0x10",
-		.driver_data = (void *) 0x10,
 		.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
 		.exit_latency = 20,
 		.target_residency = 80,
@@ -125,7 +123,6 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
 	{ /* MWAIT C3 */
 		.name = "C6-NHM",
 		.desc = "MWAIT 0x20",
-		.driver_data = (void *) 0x20,
 		.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
 		.exit_latency = 200,
 		.target_residency = 800,
@@ -137,7 +134,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
 	{ /* MWAIT C1 */
 		.name = "C1-SNB",
 		.desc = "MWAIT 0x00",
-		.driver_data = (void *) 0x00,
 		.flags = CPUIDLE_FLAG_TIME_VALID,
 		.exit_latency = 1,
 		.target_residency = 1,
@@ -145,7 +141,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
 	{ /* MWAIT C2 */
 		.name = "C3-SNB",
 		.desc = "MWAIT 0x10",
-		.driver_data = (void *) 0x10,
 		.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
 		.exit_latency = 80,
 		.target_residency = 211,
@@ -153,7 +148,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
 	{ /* MWAIT C3 */
 		.name = "C6-SNB",
 		.desc = "MWAIT 0x20",
-		.driver_data = (void *) 0x20,
 		.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
 		.exit_latency = 104,
 		.target_residency = 345,
@@ -161,7 +155,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
 	{ /* MWAIT C4 */
 		.name = "C7-SNB",
 		.desc = "MWAIT 0x30",
-		.driver_data = (void *) 0x30,
 		.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
 		.exit_latency = 109,
 		.target_residency = 345,
@@ -173,7 +166,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
 	{ /* MWAIT C1 */
 		.name = "C1-ATM",
 		.desc = "MWAIT 0x00",
-		.driver_data = (void *) 0x00,
 		.flags = CPUIDLE_FLAG_TIME_VALID,
 		.exit_latency = 1,
 		.target_residency = 4,
@@ -181,7 +173,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
 	{ /* MWAIT C2 */
 		.name = "C2-ATM",
 		.desc = "MWAIT 0x10",
-		.driver_data = (void *) 0x10,
 		.flags = CPUIDLE_FLAG_TIME_VALID,
 		.exit_latency = 20,
 		.target_residency = 80,
@@ -190,7 +181,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
 	{ /* MWAIT C4 */
 		.name = "C4-ATM",
 		.desc = "MWAIT 0x30",
-		.driver_data = (void *) 0x30,
 		.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
 		.exit_latency = 100,
 		.target_residency = 400,
@@ -199,13 +189,41 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
 	{ /* MWAIT C6 */
 		.name = "C6-ATM",
 		.desc = "MWAIT 0x52",
-		.driver_data = (void *) 0x52,
 		.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
 		.exit_latency = 140,
 		.target_residency = 560,
 		.enter = &intel_idle },
 };
 
+static int get_driver_data(int cstate)
+{
+	int driver_data;
+	switch (cstate) {
+
+	case 1:	/* MWAIT C1 */
+		driver_data = 0x00;
+		break;
+	case 2:	/* MWAIT C2 */
+		driver_data = 0x10;
+		break;
+	case 3:	/* MWAIT C3 */
+		driver_data = 0x20;
+		break;
+	case 4:	/* MWAIT C4 */
+		driver_data = 0x30;
+		break;
+	case 5:	/* MWAIT C5 */
+		driver_data = 0x40;
+		break;
+	case 6:	/* MWAIT C6 */
+		driver_data = 0x52;
+		break;
+	default:
+		driver_data = 0x00;
+	}
+	return driver_data;
+}
+
 /**
  * intel_idle
  * @dev: cpuidle_device
@@ -216,7 +234,8 @@ static int intel_idle(struct cpuidle_device *dev, int index)
 {
 	unsigned long ecx = 1; /* break on interrupt flag */
 	struct cpuidle_state *state = &dev->states[index];
-	unsigned long eax = (unsigned long)cpuidle_get_statedata(state);
+	struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
+	unsigned long eax = (unsigned long)cpuidle_get_statedata(state_usage);
 	unsigned int cstate;
 	ktime_t kt_before, kt_after;
 	s64 usec_delta;
@@ -451,6 +470,9 @@ static int intel_idle_cpuidle_devices_init(void)
 			dev->states[dev->state_count] =	/* structure copy */
 				cpuidle_state_table[cstate];
 
+			dev->states_usage[dev->state_count].driver_data =
+				(void *)get_driver_data(cstate);
+
 			dev->state_count += 1;
 		}
 
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index c6d85cf..0156540 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -28,19 +28,22 @@ struct cpuidle_device;
  * CPUIDLE DEVICE INTERFACE *
  ****************************/
 
+struct cpuidle_state_usage {
+	void		*driver_data;
+
+	unsigned long long	usage;
+	unsigned long long	time; /* in US */
+};
+
 struct cpuidle_state {
 	char		name[CPUIDLE_NAME_LEN];
 	char		desc[CPUIDLE_DESC_LEN];
-	void		*driver_data;
 
 	unsigned int	flags;
 	unsigned int	exit_latency; /* in US */
 	unsigned int	power_usage; /* in mW */
 	unsigned int	target_residency; /* in US */
 
-	unsigned long long	usage;
-	unsigned long long	time; /* in US */
-
 	int (*enter)	(struct cpuidle_device *dev,
 			int index);
 };
@@ -52,26 +55,27 @@ struct cpuidle_state {
 
 /**
  * cpuidle_get_statedata - retrieves private driver state data
- * @state: the state
+ * @st_usage: the state usage statistics
  */
-static inline void * cpuidle_get_statedata(struct cpuidle_state *state)
+static inline void *cpuidle_get_statedata(struct cpuidle_state_usage *st_usage)
 {
-	return state->driver_data;
+	return st_usage->driver_data;
 }
 
 /**
  * cpuidle_set_statedata - stores private driver state data
- * @state: the state
+ * @st_usage: the state usage statistics
  * @data: the private data
  */
 static inline void
-cpuidle_set_statedata(struct cpuidle_state *state, void *data)
+cpuidle_set_statedata(struct cpuidle_state_usage *st_usage, void *data)
 {
-	state->driver_data = data;
+	st_usage->driver_data = data;
 }
 
 struct cpuidle_state_kobj {
 	struct cpuidle_state *state;
+	struct cpuidle_state_usage *state_usage;
 	struct completion kobj_unregister;
 	struct kobject kobj;
 };
@@ -85,6 +89,7 @@ struct cpuidle_device {
 	int			last_residency;
 	int			state_count;
 	struct cpuidle_state	states[CPUIDLE_STATE_MAX];
+	struct cpuidle_state_usage	states_usage[CPUIDLE_STATE_MAX];
 	struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX];
 
 	struct list_head 	device_list;

^ permalink raw reply related

* [PATCH V8 4/4] cpuidle: Single/Global registration of idle states
From: Deepthi Dharwar @ 2011-10-03  7:47 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20111003074147.21968.86106.stgit@localhost6.localdomain6>

This patch makes the cpuidle_states structure global (single copy)
instead of per-cpu. The statistics needed on per-cpu basis
by the governor are kept per-cpu. This simplifies the cpuidle
subsystem as state registration is done by single cpu only.
Having single copy of cpuidle_states saves memory. Rare case
of asymmetric C-states can be handled within the cpuidle driver
and architectures such as POWER do not have asymmetric C-states.

Having single/global registration of all the idle states,
dynamic C-state transitions on x86 are handled by
the boot cpu. Here, the boot cpu  would disable all the devices,
re-populate the states and later enable all the devices,
irrespective of the cpu that would receive the notification first.

Reference:
https://lkml.org/lkml/2011/4/25/83

Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
Signed-off-by: Trinabh Gupta <g.trinabh@gmail.com>
Tested-by: Jean Pihet <j-pihet@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
Acked-by: Arjan van de Ven <arjan@linux.intel.com>
Acked-by: Kevin Hilman <khilman@ti.com>
---
 arch/arm/mach-at91/cpuidle.c          |   31 +++--
 arch/arm/mach-davinci/cpuidle.c       |   39 ++++---
 arch/arm/mach-exynos4/cpuidle.c       |   23 ++--
 arch/arm/mach-kirkwood/cpuidle.c      |   30 +++--
 arch/arm/mach-omap2/cpuidle34xx.c     |   73 ++++++++-----
 arch/sh/kernel/cpu/shmobile/cpuidle.c |   18 ++-
 drivers/acpi/processor_driver.c       |   20 +--
 drivers/acpi/processor_idle.c         |  191 +++++++++++++++++++++++++++++----
 drivers/cpuidle/cpuidle.c             |   45 ++------
 drivers/cpuidle/driver.c              |   25 ++++
 drivers/cpuidle/governors/ladder.c    |   28 +++--
 drivers/cpuidle/governors/menu.c      |   20 ++-
 drivers/cpuidle/sysfs.c               |    3 -
 drivers/idle/intel_idle.c             |   80 +++++++++++---
 include/acpi/processor.h              |    1 
 include/linux/cpuidle.h               |   19 ++-
 16 files changed, 439 insertions(+), 207 deletions(-)

diff --git a/arch/arm/mach-at91/cpuidle.c b/arch/arm/mach-at91/cpuidle.c
index 4696a0d..93178f6 100644
--- a/arch/arm/mach-at91/cpuidle.c
+++ b/arch/arm/mach-at91/cpuidle.c
@@ -33,6 +33,7 @@ static struct cpuidle_driver at91_idle_driver = {
 
 /* Actual code that puts the SoC in different idle states */
 static int at91_enter_idle(struct cpuidle_device *dev,
+			struct cpuidle_driver *drv,
 			       int index)
 {
 	struct timeval before, after;
@@ -64,27 +65,29 @@ static int at91_enter_idle(struct cpuidle_device *dev,
 static int at91_init_cpuidle(void)
 {
 	struct cpuidle_device *device;
-
-	cpuidle_register_driver(&at91_idle_driver);
+	struct cpuidle_driver *driver = &at91_idle_driver;
 
 	device = &per_cpu(at91_cpuidle_device, smp_processor_id());
 	device->state_count = AT91_MAX_STATES;
+	driver->state_count = AT91_MAX_STATES;
 
 	/* Wait for interrupt state */
-	device->states[0].enter = at91_enter_idle;
-	device->states[0].exit_latency = 1;
-	device->states[0].target_residency = 10000;
-	device->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
-	strcpy(device->states[0].name, "WFI");
-	strcpy(device->states[0].desc, "Wait for interrupt");
+	driver->states[0].enter = at91_enter_idle;
+	driver->states[0].exit_latency = 1;
+	driver->states[0].target_residency = 10000;
+	driver->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
+	strcpy(driver->states[0].name, "WFI");
+	strcpy(driver->states[0].desc, "Wait for interrupt");
 
 	/* Wait for interrupt and RAM self refresh state */
-	device->states[1].enter = at91_enter_idle;
-	device->states[1].exit_latency = 10;
-	device->states[1].target_residency = 10000;
-	device->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
-	strcpy(device->states[1].name, "RAM_SR");
-	strcpy(device->states[1].desc, "WFI and RAM Self Refresh");
+	driver->states[1].enter = at91_enter_idle;
+	driver->states[1].exit_latency = 10;
+	driver->states[1].target_residency = 10000;
+	driver->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
+	strcpy(driver->states[1].name, "RAM_SR");
+	strcpy(driver->states[1].desc, "WFI and RAM Self Refresh");
+
+	cpuidle_register_driver(&at91_idle_driver);
 
 	if (cpuidle_register_device(device)) {
 		printk(KERN_ERR "at91_init_cpuidle: Failed registering\n");
diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c
index f2d2f34..dbeeccd 100644
--- a/arch/arm/mach-davinci/cpuidle.c
+++ b/arch/arm/mach-davinci/cpuidle.c
@@ -78,6 +78,7 @@ static struct davinci_ops davinci_states[DAVINCI_CPUIDLE_MAX_STATES] = {
 
 /* Actual code that puts the SoC in different idle states */
 static int davinci_enter_idle(struct cpuidle_device *dev,
+				struct cpuidle_driver *drv,
 						int index)
 {
 	struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
@@ -109,6 +110,7 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev)
 {
 	int ret;
 	struct cpuidle_device *device;
+	struct cpuidle_driver *driver = &davinci_idle_driver;
 	struct davinci_cpuidle_config *pdata = pdev->dev.platform_data;
 
 	device = &per_cpu(davinci_cpuidle_device, smp_processor_id());
@@ -120,32 +122,33 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev)
 
 	ddr2_reg_base = pdata->ddr2_ctlr_base;
 
-	ret = cpuidle_register_driver(&davinci_idle_driver);
-	if (ret) {
-		dev_err(&pdev->dev, "failed to register driver\n");
-		return ret;
-	}
-
 	/* Wait for interrupt state */
-	device->states[0].enter = davinci_enter_idle;
-	device->states[0].exit_latency = 1;
-	device->states[0].target_residency = 10000;
-	device->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
-	strcpy(device->states[0].name, "WFI");
-	strcpy(device->states[0].desc, "Wait for interrupt");
+	driver->states[0].enter = davinci_enter_idle;
+	driver->states[0].exit_latency = 1;
+	driver->states[0].target_residency = 10000;
+	driver->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
+	strcpy(driver->states[0].name, "WFI");
+	strcpy(driver->states[0].desc, "Wait for interrupt");
 
 	/* Wait for interrupt and DDR self refresh state */
-	device->states[1].enter = davinci_enter_idle;
-	device->states[1].exit_latency = 10;
-	device->states[1].target_residency = 10000;
-	device->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
-	strcpy(device->states[1].name, "DDR SR");
-	strcpy(device->states[1].desc, "WFI and DDR Self Refresh");
+	driver->states[1].enter = davinci_enter_idle;
+	driver->states[1].exit_latency = 10;
+	driver->states[1].target_residency = 10000;
+	driver->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
+	strcpy(driver->states[1].name, "DDR SR");
+	strcpy(driver->states[1].desc, "WFI and DDR Self Refresh");
 	if (pdata->ddr2_pdown)
 		davinci_states[1].flags |= DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN;
 	cpuidle_set_statedata(&device->states_usage[1], &davinci_states[1]);
 
 	device->state_count = DAVINCI_CPUIDLE_MAX_STATES;
+	driver->state_count = DAVINCI_CPUIDLE_MAX_STATES;
+
+	ret = cpuidle_register_driver(&davinci_idle_driver);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register driver\n");
+		return ret;
+	}
 
 	ret = cpuidle_register_device(device);
 	if (ret) {
diff --git a/arch/arm/mach-exynos4/cpuidle.c b/arch/arm/mach-exynos4/cpuidle.c
index ea026e7..35f6502 100644
--- a/arch/arm/mach-exynos4/cpuidle.c
+++ b/arch/arm/mach-exynos4/cpuidle.c
@@ -16,6 +16,7 @@
 #include <asm/proc-fns.h>
 
 static int exynos4_enter_idle(struct cpuidle_device *dev,
+			struct cpuidle_driver *drv,
 			      int index);
 
 static struct cpuidle_state exynos4_cpuidle_set[] = {
@@ -37,6 +38,7 @@ static struct cpuidle_driver exynos4_idle_driver = {
 };
 
 static int exynos4_enter_idle(struct cpuidle_device *dev,
+				struct cpuidle_driver *drv,
 			      int index)
 {
 	struct timeval before, after;
@@ -60,22 +62,23 @@ static int __init exynos4_init_cpuidle(void)
 {
 	int i, max_cpuidle_state, cpu_id;
 	struct cpuidle_device *device;
-
+	struct cpuidle_driver *drv = &exynos4_idle_driver;
+
+	/* Setup cpuidle driver */
+	drv->state_count = (sizeof(exynos4_cpuidle_set) /
+				       sizeof(struct cpuidle_state));
+	max_cpuidle_state = drv->state_count;
+	for (i = 0; i < max_cpuidle_state; i++) {
+		memcpy(&drv->states[i], &exynos4_cpuidle_set[i],
+				sizeof(struct cpuidle_state));
+	}
 	cpuidle_register_driver(&exynos4_idle_driver);
 
 	for_each_cpu(cpu_id, cpu_online_mask) {
 		device = &per_cpu(exynos4_cpuidle_device, cpu_id);
 		device->cpu = cpu_id;
 
-		device->state_count = (sizeof(exynos4_cpuidle_set) /
-					       sizeof(struct cpuidle_state));
-
-		max_cpuidle_state = device->state_count;
-
-		for (i = 0; i < max_cpuidle_state; i++) {
-			memcpy(&device->states[i], &exynos4_cpuidle_set[i],
-					sizeof(struct cpuidle_state));
-		}
+		device->state_count = drv->state_count;
 
 		if (cpuidle_register_device(device)) {
 			printk(KERN_ERR "CPUidle register device failed\n,");
diff --git a/arch/arm/mach-kirkwood/cpuidle.c b/arch/arm/mach-kirkwood/cpuidle.c
index 358dd80..ffd690d 100644
--- a/arch/arm/mach-kirkwood/cpuidle.c
+++ b/arch/arm/mach-kirkwood/cpuidle.c
@@ -32,6 +32,7 @@ static DEFINE_PER_CPU(struct cpuidle_device, kirkwood_cpuidle_device);
 
 /* Actual code that puts the SoC in different idle states */
 static int kirkwood_enter_idle(struct cpuidle_device *dev,
+				struct cpuidle_driver *drv,
 			       int index)
 {
 	struct timeval before, after;
@@ -68,28 +69,29 @@ static int kirkwood_enter_idle(struct cpuidle_device *dev,
 static int kirkwood_init_cpuidle(void)
 {
 	struct cpuidle_device *device;
-
-	cpuidle_register_driver(&kirkwood_idle_driver);
+	struct cpuidle_driver *driver = &kirkwood_idle_driver;
 
 	device = &per_cpu(kirkwood_cpuidle_device, smp_processor_id());
 	device->state_count = KIRKWOOD_MAX_STATES;
+	driver->state_count = KIRKWOOD_MAX_STATES;
 
 	/* Wait for interrupt state */
-	device->states[0].enter = kirkwood_enter_idle;
-	device->states[0].exit_latency = 1;
-	device->states[0].target_residency = 10000;
-	device->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
-	strcpy(device->states[0].name, "WFI");
-	strcpy(device->states[0].desc, "Wait for interrupt");
+	driver->states[0].enter = kirkwood_enter_idle;
+	driver->states[0].exit_latency = 1;
+	driver->states[0].target_residency = 10000;
+	driver->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
+	strcpy(driver->states[0].name, "WFI");
+	strcpy(driver->states[0].desc, "Wait for interrupt");
 
 	/* Wait for interrupt and DDR self refresh state */
-	device->states[1].enter = kirkwood_enter_idle;
-	device->states[1].exit_latency = 10;
-	device->states[1].target_residency = 10000;
-	device->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
-	strcpy(device->states[1].name, "DDR SR");
-	strcpy(device->states[1].desc, "WFI and DDR Self Refresh");
+	driver->states[1].enter = kirkwood_enter_idle;
+	driver->states[1].exit_latency = 10;
+	driver->states[1].target_residency = 10000;
+	driver->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
+	strcpy(driver->states[1].name, "DDR SR");
+	strcpy(driver->states[1].desc, "WFI and DDR Self Refresh");
 
+	cpuidle_register_driver(&kirkwood_idle_driver);
 	if (cpuidle_register_device(device)) {
 		printk(KERN_ERR "kirkwood_init_cpuidle: Failed registering\n");
 		return -EIO;
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index d3fce7b..1fe35c2 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -88,12 +88,14 @@ static int _cpuidle_deny_idle(struct powerdomain *pwrdm,
 /**
  * omap3_enter_idle - Programs OMAP3 to enter the specified state
  * @dev: cpuidle device
+ * @drv: cpuidle driver
  * @index: the index of state to be entered
  *
  * Called from the CPUidle framework to program the device to the
  * specified target state selected by the governor.
  */
 static int omap3_enter_idle(struct cpuidle_device *dev,
+				struct cpuidle_driver *drv,
 				int index)
 {
 	struct omap3_idle_statedata *cx =
@@ -148,6 +150,7 @@ return_sleep_time:
 /**
  * next_valid_state - Find next valid C-state
  * @dev: cpuidle device
+ * @drv: cpuidle driver
  * @index: Index of currently selected c-state
  *
  * If the state corresponding to index is valid, index is returned back
@@ -158,10 +161,11 @@ return_sleep_time:
  * if it satisfies the enable_off_mode condition.
  */
 static int next_valid_state(struct cpuidle_device *dev,
+			struct cpuidle_driver *drv,
 				int index)
 {
 	struct cpuidle_state_usage *curr_usage = &dev->states_usage[index];
-	struct cpuidle_state *curr = &dev->states[index];
+	struct cpuidle_state *curr = &drv->states[index];
 	struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr_usage);
 	u32 mpu_deepest_state = PWRDM_POWER_RET;
 	u32 core_deepest_state = PWRDM_POWER_RET;
@@ -188,7 +192,7 @@ static int next_valid_state(struct cpuidle_device *dev,
 
 		/* Reach the current state starting at highest C-state */
 		for (; idx >= 0; idx--) {
-			if (&dev->states[idx] == curr) {
+			if (&drv->states[idx] == curr) {
 				next_index = idx;
 				break;
 			}
@@ -224,12 +228,14 @@ static int next_valid_state(struct cpuidle_device *dev,
 /**
  * omap3_enter_idle_bm - Checks for any bus activity
  * @dev: cpuidle device
+ * @drv: cpuidle driver
  * @index: array index of target state to be programmed
  *
  * This function checks for any pending activity and then programs
  * the device to the specified or a safer state.
  */
 static int omap3_enter_idle_bm(struct cpuidle_device *dev,
+				struct cpuidle_driver *drv,
 			       int index)
 {
 	int new_state_idx;
@@ -238,7 +244,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
 	int ret;
 
 	if (!omap3_can_sleep()) {
-		new_state_idx = dev->safe_state_index;
+		new_state_idx = drv->safe_state_index;
 		goto select_state;
 	}
 
@@ -248,7 +254,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
 	 */
 	cam_state = pwrdm_read_pwrst(cam_pd);
 	if (cam_state == PWRDM_POWER_ON) {
-		new_state_idx = dev->safe_state_index;
+		new_state_idx = drv->safe_state_index;
 		goto select_state;
 	}
 
@@ -275,10 +281,10 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
 	if (per_next_state != per_saved_state)
 		pwrdm_set_next_pwrst(per_pd, per_next_state);
 
-	new_state_idx = next_valid_state(dev, index);
+	new_state_idx = next_valid_state(dev, drv, index);
 
 select_state:
-	ret = omap3_enter_idle(dev, new_state_idx);
+	ret = omap3_enter_idle(dev, drv, new_state_idx);
 
 	/* Restore original PER state if it was modified */
 	if (per_next_state != per_saved_state)
@@ -311,22 +317,30 @@ struct cpuidle_driver omap3_idle_driver = {
 	.owner = 	THIS_MODULE,
 };
 
-/* Helper to fill the C-state common data and register the driver_data */
-static inline struct omap3_idle_statedata *_fill_cstate(
-					struct cpuidle_device *dev,
+/* Helper to fill the C-state common data*/
+static inline void _fill_cstate(struct cpuidle_driver *drv,
 					int idx, const char *descr)
 {
-	struct omap3_idle_statedata *cx = &omap3_idle_data[idx];
-	struct cpuidle_state *state = &dev->states[idx];
-	struct cpuidle_state_usage *state_usage = &dev->states_usage[idx];
+	struct cpuidle_state *state = &drv->states[idx];
 
 	state->exit_latency	= cpuidle_params_table[idx].exit_latency;
 	state->target_residency	= cpuidle_params_table[idx].target_residency;
 	state->flags		= CPUIDLE_FLAG_TIME_VALID;
 	state->enter		= omap3_enter_idle_bm;
-	cx->valid		= cpuidle_params_table[idx].valid;
 	sprintf(state->name, "C%d", idx + 1);
 	strncpy(state->desc, descr, CPUIDLE_DESC_LEN);
+
+}
+
+/* Helper to register the driver_data */
+static inline struct omap3_idle_statedata *_fill_cstate_usage(
+					struct cpuidle_device *dev,
+					int idx)
+{
+	struct omap3_idle_statedata *cx = &omap3_idle_data[idx];
+	struct cpuidle_state_usage *state_usage = &dev->states_usage[idx];
+
+	cx->valid		= cpuidle_params_table[idx].valid;
 	cpuidle_set_statedata(state_usage, cx);
 
 	return cx;
@@ -341,6 +355,7 @@ static inline struct omap3_idle_statedata *_fill_cstate(
 int __init omap3_idle_init(void)
 {
 	struct cpuidle_device *dev;
+	struct cpuidle_driver *drv = &omap3_idle_driver;
 	struct omap3_idle_statedata *cx;
 
 	mpu_pd = pwrdm_lookup("mpu_pwrdm");
@@ -348,45 +363,52 @@ int __init omap3_idle_init(void)
 	per_pd = pwrdm_lookup("per_pwrdm");
 	cam_pd = pwrdm_lookup("cam_pwrdm");
 
-	cpuidle_register_driver(&omap3_idle_driver);
+
+	drv->safe_state_index = -1;
 	dev = &per_cpu(omap3_idle_dev, smp_processor_id());
-	dev->safe_state_index = -1;
 
 	/* C1 . MPU WFI + Core active */
-	cx = _fill_cstate(dev, 0, "MPU ON + CORE ON");
-	(&dev->states[0])->enter = omap3_enter_idle;
-	dev->safe_state_index = 0;
+	_fill_cstate(drv, 0, "MPU ON + CORE ON");
+	(&drv->states[0])->enter = omap3_enter_idle;
+	drv->safe_state_index = 0;
+	cx = _fill_cstate_usage(dev, 0);
 	cx->valid = 1;	/* C1 is always valid */
 	cx->mpu_state = PWRDM_POWER_ON;
 	cx->core_state = PWRDM_POWER_ON;
 
 	/* C2 . MPU WFI + Core inactive */
-	cx = _fill_cstate(dev, 1, "MPU ON + CORE ON");
+	_fill_cstate(drv, 1, "MPU ON + CORE ON");
+	cx = _fill_cstate_usage(dev, 1);
 	cx->mpu_state = PWRDM_POWER_ON;
 	cx->core_state = PWRDM_POWER_ON;
 
 	/* C3 . MPU CSWR + Core inactive */
-	cx = _fill_cstate(dev, 2, "MPU RET + CORE ON");
+	_fill_cstate(drv, 2, "MPU RET + CORE ON");
+	cx = _fill_cstate_usage(dev, 2);
 	cx->mpu_state = PWRDM_POWER_RET;
 	cx->core_state = PWRDM_POWER_ON;
 
 	/* C4 . MPU OFF + Core inactive */
-	cx = _fill_cstate(dev, 3, "MPU OFF + CORE ON");
+	_fill_cstate(drv, 3, "MPU OFF + CORE ON");
+	cx = _fill_cstate_usage(dev, 3);
 	cx->mpu_state = PWRDM_POWER_OFF;
 	cx->core_state = PWRDM_POWER_ON;
 
 	/* C5 . MPU RET + Core RET */
-	cx = _fill_cstate(dev, 4, "MPU RET + CORE RET");
+	_fill_cstate(drv, 4, "MPU RET + CORE RET");
+	cx = _fill_cstate_usage(dev, 4);
 	cx->mpu_state = PWRDM_POWER_RET;
 	cx->core_state = PWRDM_POWER_RET;
 
 	/* C6 . MPU OFF + Core RET */
-	cx = _fill_cstate(dev, 5, "MPU OFF + CORE RET");
+	_fill_cstate(drv, 5, "MPU OFF + CORE RET");
+	cx = _fill_cstate_usage(dev, 5);
 	cx->mpu_state = PWRDM_POWER_OFF;
 	cx->core_state = PWRDM_POWER_RET;
 
 	/* C7 . MPU OFF + Core OFF */
-	cx = _fill_cstate(dev, 6, "MPU OFF + CORE OFF");
+	_fill_cstate(drv, 6, "MPU OFF + CORE OFF");
+	cx = _fill_cstate_usage(dev, 6);
 	/*
 	 * Erratum i583: implementation for ES rev < Es1.2 on 3630. We cannot
 	 * enable OFF mode in a stable form for previous revisions.
@@ -400,6 +422,9 @@ int __init omap3_idle_init(void)
 	cx->mpu_state = PWRDM_POWER_OFF;
 	cx->core_state = PWRDM_POWER_OFF;
 
+	drv->state_count = OMAP3_NUM_STATES;
+	cpuidle_register_driver(&omap3_idle_driver);
+
 	dev->state_count = OMAP3_NUM_STATES;
 	if (cpuidle_register_device(dev)) {
 		printk(KERN_ERR "%s: CPUidle register device failed\n",
diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c
index 7be50d4c..ad1012a 100644
--- a/arch/sh/kernel/cpu/shmobile/cpuidle.c
+++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c
@@ -25,6 +25,7 @@ static unsigned long cpuidle_mode[] = {
 };
 
 static int cpuidle_sleep_enter(struct cpuidle_device *dev,
+				struct cpuidle_driver *drv,
 				int index)
 {
 	unsigned long allowed_mode = arch_hwblk_sleep_mode();
@@ -64,19 +65,19 @@ static struct cpuidle_driver cpuidle_driver = {
 void sh_mobile_setup_cpuidle(void)
 {
 	struct cpuidle_device *dev = &cpuidle_dev;
+	struct cpuidle_driver *drv = &cpuidle_driver;
 	struct cpuidle_state *state;
 	int i;
 
-	cpuidle_register_driver(&cpuidle_driver);
 
 	for (i = 0; i < CPUIDLE_STATE_MAX; i++) {
-		dev->states[i].name[0] = '\0';
-		dev->states[i].desc[0] = '\0';
+		drv->states[i].name[0] = '\0';
+		drv->states[i].desc[0] = '\0';
 	}
 
 	i = CPUIDLE_DRIVER_STATE_START;
 
-	state = &dev->states[i++];
+	state = &drv->states[i++];
 	snprintf(state->name, CPUIDLE_NAME_LEN, "C1");
 	strncpy(state->desc, "SuperH Sleep Mode", CPUIDLE_DESC_LEN);
 	state->exit_latency = 1;
@@ -86,10 +87,10 @@ void sh_mobile_setup_cpuidle(void)
 	state->flags |= CPUIDLE_FLAG_TIME_VALID;
 	state->enter = cpuidle_sleep_enter;
 
-	dev->safe_state_index = i-1;
+	drv->safe_state_index = i-1;
 
 	if (sh_mobile_sleep_supported & SUSP_SH_SF) {
-		state = &dev->states[i++];
+		state = &drv->states[i++];
 		snprintf(state->name, CPUIDLE_NAME_LEN, "C2");
 		strncpy(state->desc, "SuperH Sleep Mode [SF]",
 			CPUIDLE_DESC_LEN);
@@ -102,7 +103,7 @@ void sh_mobile_setup_cpuidle(void)
 	}
 
 	if (sh_mobile_sleep_supported & SUSP_SH_STANDBY) {
-		state = &dev->states[i++];
+		state = &drv->states[i++];
 		snprintf(state->name, CPUIDLE_NAME_LEN, "C3");
 		strncpy(state->desc, "SuperH Mobile Standby Mode [SF]",
 			CPUIDLE_DESC_LEN);
@@ -114,7 +115,10 @@ void sh_mobile_setup_cpuidle(void)
 		state->enter = cpuidle_sleep_enter;
 	}
 
+	drv->state_count = i;
 	dev->state_count = i;
 
+	cpuidle_register_driver(&cpuidle_driver);
+
 	cpuidle_register_device(dev);
 }
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index a4e0f1b..9d7bc9f 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -426,7 +426,7 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb,
 
 	if (action == CPU_ONLINE && pr) {
 		acpi_processor_ppc_has_changed(pr, 0);
-		acpi_processor_cst_has_changed(pr);
+		acpi_processor_hotplug(pr);
 		acpi_processor_reevaluate_tstate(pr, action);
 		acpi_processor_tstate_has_changed(pr);
 	}
@@ -503,8 +503,7 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device)
 	acpi_processor_get_throttling_info(pr);
 	acpi_processor_get_limit_info(pr);
 
-
-	if (cpuidle_get_driver() == &acpi_idle_driver)
+	if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver)
 		acpi_processor_power_init(pr, device);
 
 	pr->cdev = thermal_cooling_device_register("Processor", device,
@@ -800,17 +799,9 @@ static int __init acpi_processor_init(void)
 
 	memset(&errata, 0, sizeof(errata));
 
-	if (!cpuidle_register_driver(&acpi_idle_driver)) {
-		printk(KERN_DEBUG "ACPI: %s registered with cpuidle\n",
-			acpi_idle_driver.name);
-	} else {
-		printk(KERN_DEBUG "ACPI: acpi_idle yielding to %s\n",
-			cpuidle_get_driver()->name);
-	}
-
 	result = acpi_bus_register_driver(&acpi_processor_driver);
 	if (result < 0)
-		goto out_cpuidle;
+		return result;
 
 	acpi_processor_install_hotplug_notify();
 
@@ -821,11 +812,6 @@ static int __init acpi_processor_init(void)
 	acpi_processor_throttling_init();
 
 	return 0;
-
-out_cpuidle:
-	cpuidle_unregister_driver(&acpi_idle_driver);
-
-	return result;
 }
 
 static void __exit acpi_processor_exit(void)
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index b98c752..24fe3af 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -741,11 +741,13 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx)
 /**
  * acpi_idle_enter_c1 - enters an ACPI C1 state-type
  * @dev: the target CPU
+ * @drv: cpuidle driver containing cpuidle state info
  * @index: index of target state
  *
  * This is equivalent to the HALT instruction.
  */
-static int acpi_idle_enter_c1(struct cpuidle_device *dev, int index)
+static int acpi_idle_enter_c1(struct cpuidle_device *dev,
+		struct cpuidle_driver *drv, int index)
 {
 	ktime_t  kt1, kt2;
 	s64 idle_time;
@@ -787,9 +789,11 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, int index)
 /**
  * acpi_idle_enter_simple - enters an ACPI state without BM handling
  * @dev: the target CPU
+ * @drv: cpuidle driver with cpuidle state information
  * @index: the index of suggested state
  */
-static int acpi_idle_enter_simple(struct cpuidle_device *dev, int index)
+static int acpi_idle_enter_simple(struct cpuidle_device *dev,
+		struct cpuidle_driver *drv, int index)
 {
 	struct acpi_processor *pr;
 	struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
@@ -869,11 +873,13 @@ static DEFINE_SPINLOCK(c3_lock);
 /**
  * acpi_idle_enter_bm - enters C3 with proper BM handling
  * @dev: the target CPU
+ * @drv: cpuidle driver containing state data
  * @index: the index of suggested state
  *
  * If BM is detected, the deepest non-C3 idle state is entered instead.
  */
-static int acpi_idle_enter_bm(struct cpuidle_device *dev, int index)
+static int acpi_idle_enter_bm(struct cpuidle_device *dev,
+		struct cpuidle_driver *drv, int index)
 {
 	struct acpi_processor *pr;
 	struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
@@ -896,9 +902,9 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, int index)
 	}
 
 	if (!cx->bm_sts_skip && acpi_idle_bm_check()) {
-		if (dev->safe_state_index >= 0) {
-			return dev->states[dev->safe_state_index].enter(dev,
-						dev->safe_state_index);
+		if (drv->safe_state_index >= 0) {
+			return drv->states[drv->safe_state_index].enter(dev,
+						drv, drv->safe_state_index);
 		} else {
 			local_irq_disable();
 			acpi_safe_halt();
@@ -993,14 +999,15 @@ struct cpuidle_driver acpi_idle_driver = {
 };
 
 /**
- * acpi_processor_setup_cpuidle - prepares and configures CPUIDLE
+ * acpi_processor_setup_cpuidle_cx - prepares and configures CPUIDLE
+ * device i.e. per-cpu data
+ *
  * @pr: the ACPI processor
  */
-static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
+static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr)
 {
 	int i, count = CPUIDLE_DRIVER_STATE_START;
 	struct acpi_processor_cx *cx;
-	struct cpuidle_state *state;
 	struct cpuidle_state_usage *state_usage;
 	struct cpuidle_device *dev = &pr->power.dev;
 
@@ -1012,18 +1019,12 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
 	}
 
 	dev->cpu = pr->id;
-	dev->safe_state_index = -1;
-	for (i = 0; i < CPUIDLE_STATE_MAX; i++) {
-		dev->states[i].name[0] = '\0';
-		dev->states[i].desc[0] = '\0';
-	}
 
 	if (max_cstate == 0)
 		max_cstate = 1;
 
 	for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) {
 		cx = &pr->power.states[i];
-		state = &dev->states[count];
 		state_usage = &dev->states_usage[count];
 
 		if (!cx->valid)
@@ -1035,8 +1036,64 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
 		    !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
 			continue;
 #endif
+
 		cpuidle_set_statedata(state_usage, cx);
 
+		count++;
+		if (count == CPUIDLE_STATE_MAX)
+			break;
+	}
+
+	dev->state_count = count;
+
+	if (!count)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * acpi_processor_setup_cpuidle states- prepares and configures cpuidle
+ * global state data i.e. idle routines
+ *
+ * @pr: the ACPI processor
+ */
+static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)
+{
+	int i, count = CPUIDLE_DRIVER_STATE_START;
+	struct acpi_processor_cx *cx;
+	struct cpuidle_state *state;
+	struct cpuidle_driver *drv = &acpi_idle_driver;
+
+	if (!pr->flags.power_setup_done)
+		return -EINVAL;
+
+	if (pr->flags.power == 0)
+		return -EINVAL;
+
+	drv->safe_state_index = -1;
+	for (i = 0; i < CPUIDLE_STATE_MAX; i++) {
+		drv->states[i].name[0] = '\0';
+		drv->states[i].desc[0] = '\0';
+	}
+
+	if (max_cstate == 0)
+		max_cstate = 1;
+
+	for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) {
+		cx = &pr->power.states[i];
+
+		if (!cx->valid)
+			continue;
+
+#ifdef CONFIG_HOTPLUG_CPU
+		if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) &&
+		    !pr->flags.has_cst &&
+		    !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
+			continue;
+#endif
+
+		state = &drv->states[count];
 		snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i);
 		strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN);
 		state->exit_latency = cx->latency;
@@ -1049,13 +1106,13 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
 				state->flags |= CPUIDLE_FLAG_TIME_VALID;
 
 			state->enter = acpi_idle_enter_c1;
-			dev->safe_state_index = count;
+			drv->safe_state_index = count;
 			break;
 
 			case ACPI_STATE_C2:
 			state->flags |= CPUIDLE_FLAG_TIME_VALID;
 			state->enter = acpi_idle_enter_simple;
-			dev->safe_state_index = count;
+			drv->safe_state_index = count;
 			break;
 
 			case ACPI_STATE_C3:
@@ -1071,7 +1128,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
 			break;
 	}
 
-	dev->state_count = count;
+	drv->state_count = count;
 
 	if (!count)
 		return -EINVAL;
@@ -1079,7 +1136,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
 	return 0;
 }
 
-int acpi_processor_cst_has_changed(struct acpi_processor *pr)
+int acpi_processor_hotplug(struct acpi_processor *pr)
 {
 	int ret = 0;
 
@@ -1100,7 +1157,7 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
 	cpuidle_disable_device(&pr->power.dev);
 	acpi_processor_get_power_info(pr);
 	if (pr->flags.power) {
-		acpi_processor_setup_cpuidle(pr);
+		acpi_processor_setup_cpuidle_cx(pr);
 		ret = cpuidle_enable_device(&pr->power.dev);
 	}
 	cpuidle_resume_and_unlock();
@@ -1108,10 +1165,72 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
 	return ret;
 }
 
+int acpi_processor_cst_has_changed(struct acpi_processor *pr)
+{
+	int cpu;
+	struct acpi_processor *_pr;
+
+	if (disabled_by_idle_boot_param())
+		return 0;
+
+	if (!pr)
+		return -EINVAL;
+
+	if (nocst)
+		return -ENODEV;
+
+	if (!pr->flags.power_setup_done)
+		return -ENODEV;
+
+	/*
+	 * FIXME:  Design the ACPI notification to make it once per
+	 * system instead of once per-cpu.  This condition is a hack
+	 * to make the code that updates C-States be called once.
+	 */
+
+	if (smp_processor_id() == 0 &&
+			cpuidle_get_driver() == &acpi_idle_driver) {
+
+		cpuidle_pause_and_lock();
+		/* Protect against cpu-hotplug */
+		get_online_cpus();
+
+		/* Disable all cpuidle devices */
+		for_each_online_cpu(cpu) {
+			_pr = per_cpu(processors, cpu);
+			if (!_pr || !_pr->flags.power_setup_done)
+				continue;
+			cpuidle_disable_device(&_pr->power.dev);
+		}
+
+		/* Populate Updated C-state information */
+		acpi_processor_setup_cpuidle_states(pr);
+
+		/* Enable all cpuidle devices */
+		for_each_online_cpu(cpu) {
+			_pr = per_cpu(processors, cpu);
+			if (!_pr || !_pr->flags.power_setup_done)
+				continue;
+			acpi_processor_get_power_info(_pr);
+			if (_pr->flags.power) {
+				acpi_processor_setup_cpuidle_cx(_pr);
+				cpuidle_enable_device(&_pr->power.dev);
+			}
+		}
+		put_online_cpus();
+		cpuidle_resume_and_unlock();
+	}
+
+	return 0;
+}
+
+static int acpi_processor_registered;
+
 int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
 			      struct acpi_device *device)
 {
 	acpi_status status = 0;
+	int retval;
 	static int first_run;
 
 	if (disabled_by_idle_boot_param())
@@ -1148,9 +1267,26 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
 	 * platforms that only support C1.
 	 */
 	if (pr->flags.power) {
-		acpi_processor_setup_cpuidle(pr);
-		if (cpuidle_register_device(&pr->power.dev))
-			return -EIO;
+		/* Register acpi_idle_driver if not already registered */
+		if (!acpi_processor_registered) {
+			acpi_processor_setup_cpuidle_states(pr);
+			retval = cpuidle_register_driver(&acpi_idle_driver);
+			if (retval)
+				return retval;
+			printk(KERN_DEBUG "ACPI: %s registered with cpuidle\n",
+					acpi_idle_driver.name);
+		}
+		/* Register per-cpu cpuidle_device. Cpuidle driver
+		 * must already be registered before registering device
+		 */
+		acpi_processor_setup_cpuidle_cx(pr);
+		retval = cpuidle_register_device(&pr->power.dev);
+		if (retval) {
+			if (acpi_processor_registered == 0)
+				cpuidle_unregister_driver(&acpi_idle_driver);
+			return retval;
+		}
+		acpi_processor_registered++;
 	}
 	return 0;
 }
@@ -1161,8 +1297,13 @@ int acpi_processor_power_exit(struct acpi_processor *pr,
 	if (disabled_by_idle_boot_param())
 		return 0;
 
-	cpuidle_unregister_device(&pr->power.dev);
-	pr->flags.power_setup_done = 0;
+	if (pr->flags.power) {
+		cpuidle_unregister_device(&pr->power.dev);
+		acpi_processor_registered--;
+		if (acpi_processor_registered == 0)
+			cpuidle_unregister_driver(&acpi_idle_driver);
+	}
 
+	pr->flags.power_setup_done = 0;
 	return 0;
 }
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 7127e92..7a57b11 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -61,6 +61,7 @@ static int __cpuidle_register_device(struct cpuidle_device *dev);
 int cpuidle_idle_call(void)
 {
 	struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
+	struct cpuidle_driver *drv = cpuidle_get_driver();
 	struct cpuidle_state *target_state;
 	int next_state, entered_state;
 
@@ -84,18 +85,18 @@ int cpuidle_idle_call(void)
 #endif
 
 	/* ask the governor for the next state */
-	next_state = cpuidle_curr_governor->select(dev);
+	next_state = cpuidle_curr_governor->select(drv, dev);
 	if (need_resched()) {
 		local_irq_enable();
 		return 0;
 	}
 
-	target_state = &dev->states[next_state];
+	target_state = &drv->states[next_state];
 
 	trace_power_start(POWER_CSTATE, next_state, dev->cpu);
 	trace_cpu_idle(next_state, dev->cpu);
 
-	entered_state = target_state->enter(dev, next_state);
+	entered_state = target_state->enter(dev, drv, next_state);
 
 	trace_power_end(dev->cpu);
 	trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu);
@@ -163,7 +164,8 @@ void cpuidle_resume_and_unlock(void)
 EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock);
 
 #ifdef CONFIG_ARCH_HAS_CPU_RELAX
-static int poll_idle(struct cpuidle_device *dev, int index)
+static int poll_idle(struct cpuidle_device *dev,
+		struct cpuidle_driver *drv, int index)
 {
 	ktime_t	t1, t2;
 	s64 diff;
@@ -183,12 +185,9 @@ static int poll_idle(struct cpuidle_device *dev, int index)
 	return index;
 }
 
-static void poll_idle_init(struct cpuidle_device *dev)
+static void poll_idle_init(struct cpuidle_driver *drv)
 {
-	struct cpuidle_state *state = &dev->states[0];
-	struct cpuidle_state_usage *state_usage = &dev->states_usage[0];
-
-	cpuidle_set_statedata(state_usage, NULL);
+	struct cpuidle_state *state = &drv->states[0];
 
 	snprintf(state->name, CPUIDLE_NAME_LEN, "POLL");
 	snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE");
@@ -199,7 +198,7 @@ static void poll_idle_init(struct cpuidle_device *dev)
 	state->enter = poll_idle;
 }
 #else
-static void poll_idle_init(struct cpuidle_device *dev) {}
+static void poll_idle_init(struct cpuidle_driver *drv) {}
 #endif /* CONFIG_ARCH_HAS_CPU_RELAX */
 
 /**
@@ -226,13 +225,13 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
 			return ret;
 	}
 
-	poll_idle_init(dev);
+	poll_idle_init(cpuidle_get_driver());
 
 	if ((ret = cpuidle_add_state_sysfs(dev)))
 		return ret;
 
 	if (cpuidle_curr_governor->enable &&
-	    (ret = cpuidle_curr_governor->enable(dev)))
+	    (ret = cpuidle_curr_governor->enable(cpuidle_get_driver(), dev)))
 		goto fail_sysfs;
 
 	for (i = 0; i < dev->state_count; i++) {
@@ -273,7 +272,7 @@ void cpuidle_disable_device(struct cpuidle_device *dev)
 	dev->enabled = 0;
 
 	if (cpuidle_curr_governor->disable)
-		cpuidle_curr_governor->disable(dev);
+		cpuidle_curr_governor->disable(cpuidle_get_driver(), dev);
 
 	cpuidle_remove_state_sysfs(dev);
 	enabled_devices--;
@@ -301,26 +300,6 @@ static int __cpuidle_register_device(struct cpuidle_device *dev)
 
 	init_completion(&dev->kobj_unregister);
 
-	/*
-	 * cpuidle driver should set the dev->power_specified bit
-	 * before registering the device if the driver provides
-	 * power_usage numbers.
-	 *
-	 * For those devices whose ->power_specified is not set,
-	 * we fill in power_usage with decreasing values as the
-	 * cpuidle code has an implicit assumption that state Cn
-	 * uses less power than C(n-1).
-	 *
-	 * With CONFIG_ARCH_HAS_CPU_RELAX, C0 is already assigned
-	 * an power value of -1.  So we use -2, -3, etc, for other
-	 * c-states.
-	 */
-	if (!dev->power_specified) {
-		int i;
-		for (i = CPUIDLE_DRIVER_STATE_START; i < dev->state_count; i++)
-			dev->states[i].power_usage = -1 - i;
-	}
-
 	per_cpu(cpuidle_devices, dev->cpu) = dev;
 	list_add(&dev->device_list, &cpuidle_detected_devices);
 	if ((ret = cpuidle_add_sysfs(sys_dev))) {
diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c
index 3f7e3ce..284d7af 100644
--- a/drivers/cpuidle/driver.c
+++ b/drivers/cpuidle/driver.c
@@ -17,6 +17,30 @@
 static struct cpuidle_driver *cpuidle_curr_driver;
 DEFINE_SPINLOCK(cpuidle_driver_lock);
 
+static void __cpuidle_register_driver(struct cpuidle_driver *drv)
+{
+	int i;
+	/*
+	 * cpuidle driver should set the drv->power_specified bit
+	 * before registering if the driver provides
+	 * power_usage numbers.
+	 *
+	 * If power_specified is not set,
+	 * we fill in power_usage with decreasing values as the
+	 * cpuidle code has an implicit assumption that state Cn
+	 * uses less power than C(n-1).
+	 *
+	 * With CONFIG_ARCH_HAS_CPU_RELAX, C0 is already assigned
+	 * an power value of -1.  So we use -2, -3, etc, for other
+	 * c-states.
+	 */
+	if (!drv->power_specified) {
+		for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++)
+			drv->states[i].power_usage = -1 - i;
+	}
+}
+
+
 /**
  * cpuidle_register_driver - registers a driver
  * @drv: the driver
@@ -34,6 +58,7 @@ int cpuidle_register_driver(struct cpuidle_driver *drv)
 		spin_unlock(&cpuidle_driver_lock);
 		return -EBUSY;
 	}
+	__cpuidle_register_driver(drv);
 	cpuidle_curr_driver = drv;
 	spin_unlock(&cpuidle_driver_lock);
 
diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c
index 6a686a7..ef6b9e4 100644
--- a/drivers/cpuidle/governors/ladder.c
+++ b/drivers/cpuidle/governors/ladder.c
@@ -60,9 +60,11 @@ static inline void ladder_do_selection(struct ladder_device *ldev,
 
 /**
  * ladder_select_state - selects the next state to enter
+ * @drv: cpuidle driver
  * @dev: the CPU
  */
-static int ladder_select_state(struct cpuidle_device *dev)
+static int ladder_select_state(struct cpuidle_driver *drv,
+				struct cpuidle_device *dev)
 {
 	struct ladder_device *ldev = &__get_cpu_var(ladder_devices);
 	struct ladder_device_state *last_state;
@@ -77,15 +79,17 @@ static int ladder_select_state(struct cpuidle_device *dev)
 
 	last_state = &ldev->states[last_idx];
 
-	if (dev->states[last_idx].flags & CPUIDLE_FLAG_TIME_VALID)
-		last_residency = cpuidle_get_last_residency(dev) - dev->states[last_idx].exit_latency;
+	if (drv->states[last_idx].flags & CPUIDLE_FLAG_TIME_VALID) {
+		last_residency = cpuidle_get_last_residency(dev) - \
+					 drv->states[last_idx].exit_latency;
+	}
 	else
 		last_residency = last_state->threshold.promotion_time + 1;
 
 	/* consider promotion */
-	if (last_idx < dev->state_count - 1 &&
+	if (last_idx < drv->state_count - 1 &&
 	    last_residency > last_state->threshold.promotion_time &&
-	    dev->states[last_idx + 1].exit_latency <= latency_req) {
+	    drv->states[last_idx + 1].exit_latency <= latency_req) {
 		last_state->stats.promotion_count++;
 		last_state->stats.demotion_count = 0;
 		if (last_state->stats.promotion_count >= last_state->threshold.promotion_count) {
@@ -96,11 +100,11 @@ static int ladder_select_state(struct cpuidle_device *dev)
 
 	/* consider demotion */
 	if (last_idx > CPUIDLE_DRIVER_STATE_START &&
-	    dev->states[last_idx].exit_latency > latency_req) {
+	    drv->states[last_idx].exit_latency > latency_req) {
 		int i;
 
 		for (i = last_idx - 1; i > CPUIDLE_DRIVER_STATE_START; i--) {
-			if (dev->states[i].exit_latency <= latency_req)
+			if (drv->states[i].exit_latency <= latency_req)
 				break;
 		}
 		ladder_do_selection(ldev, last_idx, i);
@@ -123,9 +127,11 @@ static int ladder_select_state(struct cpuidle_device *dev)
 
 /**
  * ladder_enable_device - setup for the governor
+ * @drv: cpuidle driver
  * @dev: the CPU
  */
-static int ladder_enable_device(struct cpuidle_device *dev)
+static int ladder_enable_device(struct cpuidle_driver *drv,
+				struct cpuidle_device *dev)
 {
 	int i;
 	struct ladder_device *ldev = &per_cpu(ladder_devices, dev->cpu);
@@ -134,8 +140,8 @@ static int ladder_enable_device(struct cpuidle_device *dev)
 
 	ldev->last_state_idx = CPUIDLE_DRIVER_STATE_START;
 
-	for (i = 0; i < dev->state_count; i++) {
-		state = &dev->states[i];
+	for (i = 0; i < drv->state_count; i++) {
+		state = &drv->states[i];
 		lstate = &ldev->states[i];
 
 		lstate->stats.promotion_count = 0;
@@ -144,7 +150,7 @@ static int ladder_enable_device(struct cpuidle_device *dev)
 		lstate->threshold.promotion_count = PROMOTION_COUNT;
 		lstate->threshold.demotion_count = DEMOTION_COUNT;
 
-		if (i < dev->state_count - 1)
+		if (i < drv->state_count - 1)
 			lstate->threshold.promotion_time = state->exit_latency;
 		if (i > 0)
 			lstate->threshold.demotion_time = state->exit_latency;
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index af724e8..bcbe881 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -182,7 +182,7 @@ static inline int performance_multiplier(void)
 
 static DEFINE_PER_CPU(struct menu_device, menu_devices);
 
-static void menu_update(struct cpuidle_device *dev);
+static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev);
 
 /* This implements DIV_ROUND_CLOSEST but avoids 64 bit division */
 static u64 div_round64(u64 dividend, u32 divisor)
@@ -228,9 +228,10 @@ static void detect_repeating_patterns(struct menu_device *data)
 
 /**
  * menu_select - selects the next idle state to enter
+ * @drv: cpuidle driver containing state data
  * @dev: the CPU
  */
-static int menu_select(struct cpuidle_device *dev)
+static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
 {
 	struct menu_device *data = &__get_cpu_var(menu_devices);
 	int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
@@ -240,7 +241,7 @@ static int menu_select(struct cpuidle_device *dev)
 	struct timespec t;
 
 	if (data->needs_update) {
-		menu_update(dev);
+		menu_update(drv, dev);
 		data->needs_update = 0;
 	}
 
@@ -285,8 +286,8 @@ static int menu_select(struct cpuidle_device *dev)
 	 * Find the idle state with the lowest power while satisfying
 	 * our constraints.
 	 */
-	for (i = CPUIDLE_DRIVER_STATE_START; i < dev->state_count; i++) {
-		struct cpuidle_state *s = &dev->states[i];
+	for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) {
+		struct cpuidle_state *s = &drv->states[i];
 
 		if (s->target_residency > data->predicted_us)
 			continue;
@@ -323,14 +324,15 @@ static void menu_reflect(struct cpuidle_device *dev, int index)
 
 /**
  * menu_update - attempts to guess what happened after entry
+ * @drv: cpuidle driver containing state data
  * @dev: the CPU
  */
-static void menu_update(struct cpuidle_device *dev)
+static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
 {
 	struct menu_device *data = &__get_cpu_var(menu_devices);
 	int last_idx = data->last_state_idx;
 	unsigned int last_idle_us = cpuidle_get_last_residency(dev);
-	struct cpuidle_state *target = &dev->states[last_idx];
+	struct cpuidle_state *target = &drv->states[last_idx];
 	unsigned int measured_us;
 	u64 new_factor;
 
@@ -384,9 +386,11 @@ static void menu_update(struct cpuidle_device *dev)
 
 /**
  * menu_enable_device - scans a CPU's states and does setup
+ * @drv: cpuidle driver
  * @dev: the CPU
  */
-static int menu_enable_device(struct cpuidle_device *dev)
+static int menu_enable_device(struct cpuidle_driver *drv,
+				struct cpuidle_device *dev)
 {
 	struct menu_device *data = &per_cpu(menu_devices, dev->cpu);
 
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c
index 8a1ace1..1e756e1 100644
--- a/drivers/cpuidle/sysfs.c
+++ b/drivers/cpuidle/sysfs.c
@@ -322,13 +322,14 @@ int cpuidle_add_state_sysfs(struct cpuidle_device *device)
 {
 	int i, ret = -ENOMEM;
 	struct cpuidle_state_kobj *kobj;
+	struct cpuidle_driver *drv = cpuidle_get_driver();
 
 	/* state statistics */
 	for (i = 0; i < device->state_count; i++) {
 		kobj = kzalloc(sizeof(struct cpuidle_state_kobj), GFP_KERNEL);
 		if (!kobj)
 			goto error_state;
-		kobj->state = &device->states[i];
+		kobj->state = &drv->states[i];
 		kobj->state_usage = &device->states_usage[i];
 		init_completion(&kobj->kobj_unregister);
 
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 3aa8d4c..5be9d59 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -81,7 +81,8 @@ static unsigned int mwait_substates;
 static unsigned int lapic_timer_reliable_states = (1 << 1);	 /* Default to only C1 */
 
 static struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
-static int intel_idle(struct cpuidle_device *dev, int index);
+static int intel_idle(struct cpuidle_device *dev,
+			struct cpuidle_driver *drv, int index);
 
 static struct cpuidle_state *cpuidle_state_table;
 
@@ -227,13 +228,15 @@ static int get_driver_data(int cstate)
 /**
  * intel_idle
  * @dev: cpuidle_device
+ * @drv: cpuidle driver
  * @index: index of cpuidle state
  *
  */
-static int intel_idle(struct cpuidle_device *dev, int index)
+static int intel_idle(struct cpuidle_device *dev,
+		struct cpuidle_driver *drv, int index)
 {
 	unsigned long ecx = 1; /* break on interrupt flag */
-	struct cpuidle_state *state = &dev->states[index];
+	struct cpuidle_state *state = &drv->states[index];
 	struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
 	unsigned long eax = (unsigned long)cpuidle_get_statedata(state_usage);
 	unsigned int cstate;
@@ -420,6 +423,60 @@ static void intel_idle_cpuidle_devices_uninit(void)
 	return;
 }
 /*
+ * intel_idle_cpuidle_driver_init()
+ * allocate, initialize cpuidle_states
+ */
+static int intel_idle_cpuidle_driver_init(void)
+{
+	int cstate;
+	struct cpuidle_driver *drv = &intel_idle_driver;
+
+	drv->state_count = 1;
+
+	for (cstate = 1; cstate < MWAIT_MAX_NUM_CSTATES; ++cstate) {
+		int num_substates;
+
+		if (cstate > max_cstate) {
+			printk(PREFIX "max_cstate %d reached\n",
+				max_cstate);
+			break;
+		}
+
+		/* does the state exist in CPUID.MWAIT? */
+		num_substates = (mwait_substates >> ((cstate) * 4))
+					& MWAIT_SUBSTATE_MASK;
+		if (num_substates == 0)
+			continue;
+		/* is the state not enabled? */
+		if (cpuidle_state_table[cstate].enter == NULL) {
+			/* does the driver not know about the state? */
+			if (*cpuidle_state_table[cstate].name == '\0')
+				pr_debug(PREFIX "unaware of model 0x%x"
+					" MWAIT %d please"
+					" contact lenb at kernel.org",
+				boot_cpu_data.x86_model, cstate);
+			continue;
+		}
+
+		if ((cstate > 2) &&
+			!boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
+			mark_tsc_unstable("TSC halts in idle"
+					" states deeper than C2");
+
+		drv->states[drv->state_count] =	/* structure copy */
+			cpuidle_state_table[cstate];
+
+		drv->state_count += 1;
+	}
+
+	if (auto_demotion_disable_flags)
+		smp_call_function(auto_demotion_disable, NULL, 1);
+
+	return 0;
+}
+
+
+/*
  * intel_idle_cpuidle_devices_init()
  * allocate, initialize, register cpuidle_devices
  */
@@ -453,23 +510,9 @@ static int intel_idle_cpuidle_devices_init(void)
 				continue;
 			/* is the state not enabled? */
 			if (cpuidle_state_table[cstate].enter == NULL) {
-				/* does the driver not know about the state? */
-				if (*cpuidle_state_table[cstate].name == '\0')
-					pr_debug(PREFIX "unaware of model 0x%x"
-						" MWAIT %d please"
-						" contact lenb at kernel.org",
-					boot_cpu_data.x86_model, cstate);
 				continue;
 			}
 
-			if ((cstate > 2) &&
-				!boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
-				mark_tsc_unstable("TSC halts in idle"
-					" states deeper than C2");
-
-			dev->states[dev->state_count] =	/* structure copy */
-				cpuidle_state_table[cstate];
-
 			dev->states_usage[dev->state_count].driver_data =
 				(void *)get_driver_data(cstate);
 
@@ -484,8 +527,6 @@ static int intel_idle_cpuidle_devices_init(void)
 			return -EIO;
 		}
 	}
-	if (auto_demotion_disable_flags)
-		smp_call_function(auto_demotion_disable, NULL, 1);
 
 	return 0;
 }
@@ -503,6 +544,7 @@ static int __init intel_idle_init(void)
 	if (retval)
 		return retval;
 
+	intel_idle_cpuidle_driver_init();
 	retval = cpuidle_register_driver(&intel_idle_driver);
 	if (retval) {
 		printk(KERN_DEBUG PREFIX "intel_idle yielding to %s",
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index 67055f1..610f6fb 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -329,6 +329,7 @@ extern void acpi_processor_throttling_init(void);
 int acpi_processor_power_init(struct acpi_processor *pr,
 			      struct acpi_device *device);
 int acpi_processor_cst_has_changed(struct acpi_processor *pr);
+int acpi_processor_hotplug(struct acpi_processor *pr);
 int acpi_processor_power_exit(struct acpi_processor *pr,
 			      struct acpi_device *device);
 int acpi_processor_suspend(struct acpi_device * device, pm_message_t state);
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index 0156540..c904188 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -22,6 +22,7 @@
 #define CPUIDLE_DESC_LEN	32
 
 struct cpuidle_device;
+struct cpuidle_driver;
 
 
 /****************************
@@ -45,6 +46,7 @@ struct cpuidle_state {
 	unsigned int	target_residency; /* in US */
 
 	int (*enter)	(struct cpuidle_device *dev,
+			struct cpuidle_driver *drv,
 			int index);
 };
 
@@ -83,12 +85,10 @@ struct cpuidle_state_kobj {
 struct cpuidle_device {
 	unsigned int		registered:1;
 	unsigned int		enabled:1;
-	unsigned int		power_specified:1;
 	unsigned int		cpu;
 
 	int			last_residency;
 	int			state_count;
-	struct cpuidle_state	states[CPUIDLE_STATE_MAX];
 	struct cpuidle_state_usage	states_usage[CPUIDLE_STATE_MAX];
 	struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX];
 
@@ -96,7 +96,6 @@ struct cpuidle_device {
 	struct kobject		kobj;
 	struct completion	kobj_unregister;
 	void			*governor_data;
-	int			safe_state_index;
 };
 
 DECLARE_PER_CPU(struct cpuidle_device *, cpuidle_devices);
@@ -120,6 +119,11 @@ static inline int cpuidle_get_last_residency(struct cpuidle_device *dev)
 struct cpuidle_driver {
 	char			name[CPUIDLE_NAME_LEN];
 	struct module 		*owner;
+
+	unsigned int		power_specified:1;
+	struct cpuidle_state	states[CPUIDLE_STATE_MAX];
+	int			state_count;
+	int			safe_state_index;
 };
 
 #ifdef CONFIG_CPU_IDLE
@@ -166,10 +170,13 @@ struct cpuidle_governor {
 	struct list_head 	governor_list;
 	unsigned int		rating;
 
-	int  (*enable)		(struct cpuidle_device *dev);
-	void (*disable)		(struct cpuidle_device *dev);
+	int  (*enable)		(struct cpuidle_driver *drv,
+					struct cpuidle_device *dev);
+	void (*disable)		(struct cpuidle_driver *drv,
+					struct cpuidle_device *dev);
 
-	int  (*select)		(struct cpuidle_device *dev);
+	int  (*select)		(struct cpuidle_driver *drv,
+					struct cpuidle_device *dev);
 	void (*reflect)		(struct cpuidle_device *dev, int index);
 
 	struct module 		*owner;

^ permalink raw reply related

* [GIT PULL] at91 fixes for 3.1
From: Nicolas Ferre @ 2011-10-03  8:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201109302217.13937.arnd@arndb.de>

On 09/30/2011 10:17 PM, Arnd Bergmann :
> On Wednesday 28 September 2011, Nicolas FERRE wrote:
>> Here is a couple of fixes that may be included in 3.1-final.
>> The Kconfig modification will allow to select the PWM driver for SAM9G45 
>> SoC. This will also benefit to stable kernels.
>> The new defconfig for SAM9G45 family will allow us to better monitor the 
>> health of this port through automatic compilation mechanism. I find it 
>> interesting to have it included the sooner.
>>
>> The pull is based on the following changes since commit 
>> a102a9ece5489e1718cd7543aa079082450ac3a2:
>>
>>    Linux 3.1-rc8 (2011-09-27 15:48:34 -0700)
>>
>> are available in the git repository at:
>>    git://github.com/at91linux/linux-at91.git at91-fixes
> 
> Hi Nicolas,
> 
> I've pulled them into the fixes branch now. My feeling however is that
> these by themselves are not reason enough to send a pull request to Linus,
> so they will probably be the first thing I send in the 3.2 merge window,
> unless some other important fixes appear.

Ok, that makes sense.

Thanks Arnd, bye,
-- 
Nicolas Ferre

^ permalink raw reply

* [PATCH 2/2] pinmux: add a driver for the U300 pinmux
From: Linus Walleij @ 2011-10-03  8:18 UTC (permalink / raw)
  To: linux-arm-kernel

From: Linus Walleij <linus.walleij@linaro.org>

This adds a driver for the U300 pinmux portions of the system
controller "SYSCON". It also serves as an example of how to use
the pinmux subsystem. This driver also houses the platform data
for the only supported platform.

This deletes the old U300 driver in arch/arm/mach-u300 and
replace it with a driver using the new subsystem.

The new driver is considerably fatter than the old one, but it
also registers all 467 pins of the system and adds the power
and EMIF pin groups and corresponding functions. The idea
is to use this driver as a a reference for other
implementation so it needs to be as complete and verbose
as possible.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
ChangeLog v7->v9:

- Use devm_kzalloc()/devm_kfree() to allocate memory

- Merge the pinmux-u300.h header file into the the driver
  file.
---
 arch/arm/mach-u300/Kconfig               |    2 +
 arch/arm/mach-u300/Makefile              |    2 +-
 arch/arm/mach-u300/core.c                |   84 +++-
 arch/arm/mach-u300/include/mach/syscon.h |  136 ----
 arch/arm/mach-u300/mmc.c                 |   16 -
 arch/arm/mach-u300/padmux.c              |  367 ----------
 arch/arm/mach-u300/padmux.h              |   39 -
 arch/arm/mach-u300/spi.c                 |   20 -
 drivers/pinctrl/Kconfig                  |    7 +
 drivers/pinctrl/Makefile                 |    1 +
 drivers/pinctrl/pinmux-u300.c            | 1148 ++++++++++++++++++++++++++++++
 11 files changed, 1241 insertions(+), 581 deletions(-)
 delete mode 100644 arch/arm/mach-u300/padmux.c
 delete mode 100644 arch/arm/mach-u300/padmux.h
 create mode 100644 drivers/pinctrl/pinmux-u300.c

diff --git a/arch/arm/mach-u300/Kconfig b/arch/arm/mach-u300/Kconfig
index 32a7b0f..449fd6a 100644
--- a/arch/arm/mach-u300/Kconfig
+++ b/arch/arm/mach-u300/Kconfig
@@ -6,6 +6,8 @@ comment "ST-Ericsson Mobile Platform Products"
 
 config MACH_U300
 	bool "U300"
+	select PINCTRL
+	select PINMUX_U300
 
 comment "ST-Ericsson U300/U330/U335/U365 Feature Selections"
 
diff --git a/arch/arm/mach-u300/Makefile b/arch/arm/mach-u300/Makefile
index 8fd354a..2855381 100644
--- a/arch/arm/mach-u300/Makefile
+++ b/arch/arm/mach-u300/Makefile
@@ -2,7 +2,7 @@
 # Makefile for the linux kernel, U300 machine.
 #
 
-obj-y		:= core.o clock.o timer.o padmux.o
+obj-y		:= core.o clock.o timer.o
 obj-m		:=
 obj-n		:=
 obj-		:=
diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c
index 399c89f..2f5929b 100644
--- a/arch/arm/mach-u300/core.c
+++ b/arch/arm/mach-u300/core.c
@@ -25,6 +25,8 @@
 #include <linux/err.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/fsmc.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinmux.h>
 
 #include <asm/types.h>
 #include <asm/setup.h>
@@ -1535,6 +1537,14 @@ static struct coh901318_platform coh901318_platform = {
 	.max_channels = U300_DMA_CHANNELS,
 };
 
+static struct resource pinmux_resources[] = {
+	{
+		.start = U300_SYSCON_BASE,
+		.end   = U300_SYSCON_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
 static struct platform_device wdog_device = {
 	.name = "coh901327_wdog",
 	.id = -1,
@@ -1630,6 +1640,72 @@ static struct platform_device dma_device = {
 	},
 };
 
+static struct platform_device pinmux_device = {
+	.name = "pinmux-u300",
+	.id = -1,
+	.num_resources = ARRAY_SIZE(pinmux_resources),
+	.resource = pinmux_resources,
+};
+
+/* Pinmux settings */
+static struct pinmux_map u300_pinmux_map[] = {
+	/* anonymous maps for chip power and EMIFs */
+	PINMUX_MAP_PRIMARY_SYS_HOG("POWER", "power"),
+	PINMUX_MAP_PRIMARY_SYS_HOG("EMIF0", "emif0"),
+	PINMUX_MAP_PRIMARY_SYS_HOG("EMIF1", "emif1"),
+	/* per-device maps for MMC/SD, SPI and UART */
+	PINMUX_MAP_PRIMARY("MMCSD", "mmc0", "mmci"),
+	PINMUX_MAP_PRIMARY("SPI", "spi0", "pl022"),
+	PINMUX_MAP_PRIMARY("UART0", "uart0", "uart0"),
+};
+
+struct u300_mux_hog {
+	const char *name;
+	struct device *dev;
+	struct pinmux *pmx;
+};
+
+static struct u300_mux_hog u300_mux_hogs[] = {
+	{
+		.name = "uart0",
+		.dev = &uart0_device.dev,
+	},
+	{
+		.name = "spi0",
+		.dev = &pl022_device.dev,
+	},
+	{
+		.name = "mmc0",
+		.dev = &mmcsd_device.dev,
+	},
+};
+
+static int __init u300_pinmux_fetch(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(u300_mux_hogs); i++) {
+		struct pinmux *pmx;
+		int ret;
+
+		pmx = pinmux_get(u300_mux_hogs[i].dev, NULL);
+		if (IS_ERR(pmx)) {
+			pr_err("u300: could not get pinmux hog %s\n",
+			       u300_mux_hogs[i].name);
+			continue;
+		}
+		ret = pinmux_enable(pmx);
+		if (ret) {
+			pr_err("u300: could enable pinmux hog %s\n",
+			       u300_mux_hogs[i].name);
+			continue;
+		}
+		u300_mux_hogs[i].pmx = pmx;
+	}
+	return 0;
+}
+subsys_initcall(u300_pinmux_fetch);
+
 /*
  * Notice that AMBA devices are initialized before platform devices.
  *
@@ -1643,10 +1719,10 @@ static struct platform_device *platform_devs[] __initdata = {
 	&gpio_device,
 	&nand_device,
 	&wdog_device,
-	&ave_device
+	&ave_device,
+	&pinmux_device,
 };
 
-
 /*
  * Interrupts: the U300 platforms have two pl190 ARM PrimeCells connected
  * together so some interrupts are connected to the first one and some
@@ -1828,6 +1904,10 @@ void __init u300_init_devices(void)
 
 	u300_assign_physmem();
 
+	/* Initialize pinmuxing */
+	pinmux_register_mappings(u300_pinmux_map,
+				 ARRAY_SIZE(u300_pinmux_map));
+
 	/* Register subdevices on the I2C buses */
 	u300_i2c_register_board_devices();
 
diff --git a/arch/arm/mach-u300/include/mach/syscon.h b/arch/arm/mach-u300/include/mach/syscon.h
index 7444f5c..6e84f07 100644
--- a/arch/arm/mach-u300/include/mach/syscon.h
+++ b/arch/arm/mach-u300/include/mach/syscon.h
@@ -234,91 +234,6 @@
 #define U300_SYSCON_ECCR_EMIF_1_RET_OUT_CLK_EN_N_DISABLE	(0x0004)
 #define U300_SYSCON_ECCR_EMIF_MEMCLK_RET_EN_N_DISABLE		(0x0002)
 #define U300_SYSCON_ECCR_EMIF_SDRCLK_RET_EN_N_DISABLE		(0x0001)
-/* PAD MUX Control register 1 (LOW) 16bit (R/W) */
-#define U300_SYSCON_PMC1LR					(0x007C)
-#define U300_SYSCON_PMC1LR_MASK					(0xFFFF)
-#define U300_SYSCON_PMC1LR_CDI_MASK				(0xC000)
-#define U300_SYSCON_PMC1LR_CDI_CDI				(0x0000)
-#define U300_SYSCON_PMC1LR_CDI_EMIF				(0x4000)
-#ifdef CONFIG_MACH_U300_BS335
-#define U300_SYSCON_PMC1LR_CDI_CDI2				(0x8000)
-#define U300_SYSCON_PMC1LR_CDI_WCDMA_APP_GPIO			(0xC000)
-#elif CONFIG_MACH_U300_BS365
-#define U300_SYSCON_PMC1LR_CDI_GPIO				(0x8000)
-#define U300_SYSCON_PMC1LR_CDI_WCDMA				(0xC000)
-#endif
-#define U300_SYSCON_PMC1LR_PDI_MASK				(0x3000)
-#define U300_SYSCON_PMC1LR_PDI_PDI				(0x0000)
-#define U300_SYSCON_PMC1LR_PDI_EGG				(0x1000)
-#define U300_SYSCON_PMC1LR_PDI_WCDMA				(0x3000)
-#define U300_SYSCON_PMC1LR_MMCSD_MASK				(0x0C00)
-#define U300_SYSCON_PMC1LR_MMCSD_MMCSD				(0x0000)
-#define U300_SYSCON_PMC1LR_MMCSD_MSPRO				(0x0400)
-#define U300_SYSCON_PMC1LR_MMCSD_DSP				(0x0800)
-#define U300_SYSCON_PMC1LR_MMCSD_WCDMA				(0x0C00)
-#define U300_SYSCON_PMC1LR_ETM_MASK				(0x0300)
-#define U300_SYSCON_PMC1LR_ETM_ACC				(0x0000)
-#define U300_SYSCON_PMC1LR_ETM_APP				(0x0100)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS2_MASK			(0x00C0)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS2_STATIC			(0x0000)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS2_NFIF			(0x0040)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS2_SDRAM			(0x0080)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS2_STATIC_2GB		(0x00C0)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS1_MASK			(0x0030)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS1_STATIC			(0x0000)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS1_NFIF			(0x0010)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS1_SDRAM			(0x0020)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS1_SEMI			(0x0030)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS0_MASK			(0x000C)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS0_STATIC			(0x0000)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS0_NFIF			(0x0004)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS0_SDRAM			(0x0008)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS0_SEMI			(0x000C)
-#define U300_SYSCON_PMC1LR_EMIF_1_MASK				(0x0003)
-#define U300_SYSCON_PMC1LR_EMIF_1_STATIC			(0x0000)
-#define U300_SYSCON_PMC1LR_EMIF_1_SDRAM0			(0x0001)
-#define U300_SYSCON_PMC1LR_EMIF_1_SDRAM1			(0x0002)
-#define U300_SYSCON_PMC1LR_EMIF_1				(0x0003)
-/* PAD MUX Control register 2 (HIGH) 16bit (R/W) */
-#define U300_SYSCON_PMC1HR					(0x007E)
-#define U300_SYSCON_PMC1HR_MASK					(0xFFFF)
-#define U300_SYSCON_PMC1HR_MISC_2_MASK				(0xC000)
-#define U300_SYSCON_PMC1HR_MISC_2_APP_GPIO			(0x0000)
-#define U300_SYSCON_PMC1HR_MISC_2_MSPRO				(0x4000)
-#define U300_SYSCON_PMC1HR_MISC_2_DSP				(0x8000)
-#define U300_SYSCON_PMC1HR_MISC_2_AAIF				(0xC000)
-#define U300_SYSCON_PMC1HR_APP_GPIO_2_MASK			(0x3000)
-#define U300_SYSCON_PMC1HR_APP_GPIO_2_APP_GPIO			(0x0000)
-#define U300_SYSCON_PMC1HR_APP_GPIO_2_NFIF			(0x1000)
-#define U300_SYSCON_PMC1HR_APP_GPIO_2_DSP			(0x2000)
-#define U300_SYSCON_PMC1HR_APP_GPIO_2_AAIF			(0x3000)
-#define U300_SYSCON_PMC1HR_APP_GPIO_1_MASK			(0x0C00)
-#define U300_SYSCON_PMC1HR_APP_GPIO_1_APP_GPIO			(0x0000)
-#define U300_SYSCON_PMC1HR_APP_GPIO_1_MMC			(0x0400)
-#define U300_SYSCON_PMC1HR_APP_GPIO_1_DSP			(0x0800)
-#define U300_SYSCON_PMC1HR_APP_GPIO_1_AAIF			(0x0C00)
-#define U300_SYSCON_PMC1HR_APP_SPI_CS_2_MASK			(0x0300)
-#define U300_SYSCON_PMC1HR_APP_SPI_CS_2_APP_GPIO		(0x0000)
-#define U300_SYSCON_PMC1HR_APP_SPI_CS_2_SPI			(0x0100)
-#define U300_SYSCON_PMC1HR_APP_SPI_CS_2_AAIF			(0x0300)
-#define U300_SYSCON_PMC1HR_APP_SPI_CS_1_MASK			(0x00C0)
-#define U300_SYSCON_PMC1HR_APP_SPI_CS_1_APP_GPIO		(0x0000)
-#define U300_SYSCON_PMC1HR_APP_SPI_CS_1_SPI			(0x0040)
-#define U300_SYSCON_PMC1HR_APP_SPI_CS_1_AAIF			(0x00C0)
-#define U300_SYSCON_PMC1HR_APP_SPI_2_MASK			(0x0030)
-#define U300_SYSCON_PMC1HR_APP_SPI_2_APP_GPIO			(0x0000)
-#define U300_SYSCON_PMC1HR_APP_SPI_2_SPI			(0x0010)
-#define U300_SYSCON_PMC1HR_APP_SPI_2_DSP			(0x0020)
-#define U300_SYSCON_PMC1HR_APP_SPI_2_AAIF			(0x0030)
-#define U300_SYSCON_PMC1HR_APP_UART0_2_MASK			(0x000C)
-#define U300_SYSCON_PMC1HR_APP_UART0_2_APP_GPIO			(0x0000)
-#define U300_SYSCON_PMC1HR_APP_UART0_2_UART0			(0x0004)
-#define U300_SYSCON_PMC1HR_APP_UART0_2_NFIF_CS			(0x0008)
-#define U300_SYSCON_PMC1HR_APP_UART0_2_AAIF			(0x000C)
-#define U300_SYSCON_PMC1HR_APP_UART0_1_MASK			(0x0003)
-#define U300_SYSCON_PMC1HR_APP_UART0_1_APP_GPIO			(0x0000)
-#define U300_SYSCON_PMC1HR_APP_UART0_1_UART0			(0x0001)
-#define U300_SYSCON_PMC1HR_APP_UART0_1_AAIF			(0x0003)
 /* Step one for killing the applications system 16bit (-/W) */
 #define U300_SYSCON_KA1R					(0x0080)
 #define U300_SYSCON_KA1R_MASK					(0xFFFF)
@@ -357,57 +272,6 @@
 #define U300_SYSCON_PUCR_EMIF_1_16BIT_PU_ENABLE			(0x0080)
 #define U300_SYSCON_PUCR_EMIF_1_8BIT_PU_ENABLE			(0x0040)
 #define U300_SYSCON_PUCR_KEY_IN_PU_EN_MASK			(0x003F)
-/* Padmux 2 control */
-#define U300_SYSCON_PMC2R					(0x100)
-#define U300_SYSCON_PMC2R_APP_MISC_0_MASK			(0x00C0)
-#define U300_SYSCON_PMC2R_APP_MISC_0_APP_GPIO			(0x0000)
-#define U300_SYSCON_PMC2R_APP_MISC_0_EMIF_SDRAM			(0x0040)
-#define U300_SYSCON_PMC2R_APP_MISC_0_MMC			(0x0080)
-#define U300_SYSCON_PMC2R_APP_MISC_0_CDI2			(0x00C0)
-#define U300_SYSCON_PMC2R_APP_MISC_1_MASK			(0x0300)
-#define U300_SYSCON_PMC2R_APP_MISC_1_APP_GPIO			(0x0000)
-#define U300_SYSCON_PMC2R_APP_MISC_1_EMIF_SDRAM			(0x0100)
-#define U300_SYSCON_PMC2R_APP_MISC_1_MMC			(0x0200)
-#define U300_SYSCON_PMC2R_APP_MISC_1_CDI2			(0x0300)
-#define U300_SYSCON_PMC2R_APP_MISC_2_MASK			(0x0C00)
-#define U300_SYSCON_PMC2R_APP_MISC_2_APP_GPIO			(0x0000)
-#define U300_SYSCON_PMC2R_APP_MISC_2_EMIF_SDRAM			(0x0400)
-#define U300_SYSCON_PMC2R_APP_MISC_2_MMC			(0x0800)
-#define U300_SYSCON_PMC2R_APP_MISC_2_CDI2			(0x0C00)
-#define U300_SYSCON_PMC2R_APP_MISC_3_MASK			(0x3000)
-#define U300_SYSCON_PMC2R_APP_MISC_3_APP_GPIO			(0x0000)
-#define U300_SYSCON_PMC2R_APP_MISC_3_EMIF_SDRAM			(0x1000)
-#define U300_SYSCON_PMC2R_APP_MISC_3_MMC			(0x2000)
-#define U300_SYSCON_PMC2R_APP_MISC_3_CDI2			(0x3000)
-#define U300_SYSCON_PMC2R_APP_MISC_4_MASK			(0xC000)
-#define U300_SYSCON_PMC2R_APP_MISC_4_APP_GPIO			(0x0000)
-#define U300_SYSCON_PMC2R_APP_MISC_4_EMIF_SDRAM			(0x4000)
-#define U300_SYSCON_PMC2R_APP_MISC_4_MMC			(0x8000)
-#define U300_SYSCON_PMC2R_APP_MISC_4_ACC_GPIO			(0xC000)
-/* TODO: More SYSCON registers missing */
-#define U300_SYSCON_PMC3R					(0x10c)
-#define U300_SYSCON_PMC3R_APP_MISC_11_MASK			(0xc000)
-#define U300_SYSCON_PMC3R_APP_MISC_11_SPI			(0x4000)
-#define U300_SYSCON_PMC3R_APP_MISC_10_MASK			(0x3000)
-#define U300_SYSCON_PMC3R_APP_MISC_10_SPI			(0x1000)
-/* TODO: Missing other configs */
-#define U300_SYSCON_PMC4R					(0x168)
-#define U300_SYSCON_PMC4R_APP_MISC_12_MASK			(0x0003)
-#define U300_SYSCON_PMC4R_APP_MISC_12_APP_GPIO			(0x0000)
-#define U300_SYSCON_PMC4R_APP_MISC_13_MASK			(0x000C)
-#define U300_SYSCON_PMC4R_APP_MISC_13_CDI			(0x0000)
-#define U300_SYSCON_PMC4R_APP_MISC_13_SMIA			(0x0004)
-#define U300_SYSCON_PMC4R_APP_MISC_13_SMIA2			(0x0008)
-#define U300_SYSCON_PMC4R_APP_MISC_13_APP_GPIO			(0x000C)
-#define U300_SYSCON_PMC4R_APP_MISC_14_MASK			(0x0030)
-#define U300_SYSCON_PMC4R_APP_MISC_14_CDI			(0x0000)
-#define U300_SYSCON_PMC4R_APP_MISC_14_SMIA			(0x0010)
-#define U300_SYSCON_PMC4R_APP_MISC_14_CDI2			(0x0020)
-#define U300_SYSCON_PMC4R_APP_MISC_14_APP_GPIO			(0x0030)
-#define U300_SYSCON_PMC4R_APP_MISC_16_MASK			(0x0300)
-#define U300_SYSCON_PMC4R_APP_MISC_16_APP_GPIO_13		(0x0000)
-#define U300_SYSCON_PMC4R_APP_MISC_16_APP_UART1_CTS		(0x0100)
-#define U300_SYSCON_PMC4R_APP_MISC_16_EMIF_1_STATIC_CS5_N	(0x0200)
 /* SYS_0_CLK_CONTROL first clock control 16bit (R/W) */
 #define U300_SYSCON_S0CCR					(0x120)
 #define U300_SYSCON_S0CCR_FIELD_MASK				(0x43FF)
diff --git a/arch/arm/mach-u300/mmc.c b/arch/arm/mach-u300/mmc.c
index 677ccef..d5e4a98 100644
--- a/arch/arm/mach-u300/mmc.c
+++ b/arch/arm/mach-u300/mmc.c
@@ -21,7 +21,6 @@
 #include <mach/dma_channels.h>
 
 #include "mmc.h"
-#include "padmux.h"
 
 static struct mmci_platform_data mmc0_plat_data = {
 	/*
@@ -45,24 +44,9 @@ static struct mmci_platform_data mmc0_plat_data = {
 int __devinit mmc_init(struct amba_device *adev)
 {
 	struct device *mmcsd_device = &adev->dev;
-	struct pmx *pmx;
 	int ret = 0;
 
 	mmcsd_device->platform_data = &mmc0_plat_data;
 
-	/*
-	 * Setup padmuxing for MMC. Since this must always be
-	 * compiled into the kernel, pmx is never released.
-	 */
-	pmx = pmx_get(mmcsd_device, U300_APP_PMX_MMC_SETTING);
-
-	if (IS_ERR(pmx))
-		pr_warning("Could not get padmux handle\n");
-	else {
-		ret = pmx_activate(mmcsd_device, pmx);
-		if (IS_ERR_VALUE(ret))
-			pr_warning("Could not activate padmuxing\n");
-	}
-
 	return ret;
 }
diff --git a/arch/arm/mach-u300/padmux.c b/arch/arm/mach-u300/padmux.c
deleted file mode 100644
index 4c93c6c..0000000
--- a/arch/arm/mach-u300/padmux.c
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- *
- * arch/arm/mach-u300/padmux.c
- *
- *
- * Copyright (C) 2009 ST-Ericsson AB
- * License terms: GNU General Public License (GPL) version 2
- * U300 PADMUX functions
- * Author: Martin Persson <martin.persson@stericsson.com>
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/errno.h>
-#include <linux/io.h>
-#include <linux/mutex.h>
-#include <linux/string.h>
-#include <linux/bug.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <mach/u300-regs.h>
-#include <mach/syscon.h>
-#include "padmux.h"
-
-static DEFINE_MUTEX(pmx_mutex);
-
-const u32 pmx_registers[] = {
-	(U300_SYSCON_VBASE + U300_SYSCON_PMC1LR),
-	(U300_SYSCON_VBASE + U300_SYSCON_PMC1HR),
-	(U300_SYSCON_VBASE + U300_SYSCON_PMC2R),
-	(U300_SYSCON_VBASE + U300_SYSCON_PMC3R),
-	(U300_SYSCON_VBASE + U300_SYSCON_PMC4R)
-};
-
-/* High level functionality */
-
-/* Lazy dog:
- * onmask = {
- *   {"PMC1LR" mask, "PMC1LR" value},
- *   {"PMC1HR" mask, "PMC1HR" value},
- *   {"PMC2R"  mask, "PMC2R"  value},
- *   {"PMC3R"  mask, "PMC3R"  value},
- *   {"PMC4R"  mask, "PMC4R"  value}
- * }
- */
-static struct pmx mmc_setting = {
-	.setting = U300_APP_PMX_MMC_SETTING,
-	.default_on = false,
-	.activated = false,
-	.name = "MMC",
-	.onmask = {
-		   {U300_SYSCON_PMC1LR_MMCSD_MASK,
-		    U300_SYSCON_PMC1LR_MMCSD_MMCSD},
-		   {0, 0},
-		   {0, 0},
-		   {0, 0},
-		   {U300_SYSCON_PMC4R_APP_MISC_12_MASK,
-		    U300_SYSCON_PMC4R_APP_MISC_12_APP_GPIO}
-		   },
-};
-
-static struct pmx spi_setting = {
-	.setting = U300_APP_PMX_SPI_SETTING,
-	.default_on = false,
-	.activated = false,
-	.name = "SPI",
-	.onmask = {{0, 0},
-		   {U300_SYSCON_PMC1HR_APP_SPI_2_MASK |
-		    U300_SYSCON_PMC1HR_APP_SPI_CS_1_MASK |
-		    U300_SYSCON_PMC1HR_APP_SPI_CS_2_MASK,
-		    U300_SYSCON_PMC1HR_APP_SPI_2_SPI |
-		    U300_SYSCON_PMC1HR_APP_SPI_CS_1_SPI |
-		    U300_SYSCON_PMC1HR_APP_SPI_CS_2_SPI},
-		   {0, 0},
-		   {0, 0},
-		   {0, 0}
-		   },
-};
-
-/* Available padmux settings */
-static struct pmx *pmx_settings[] = {
-	&mmc_setting,
-	&spi_setting,
-};
-
-static void update_registers(struct pmx *pmx, bool activate)
-{
-	u16 regval, val, mask;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(pmx_registers); i++) {
-		if (activate)
-			val = pmx->onmask[i].val;
-		else
-			val = 0;
-
-		mask = pmx->onmask[i].mask;
-		if (mask != 0) {
-			regval = readw(pmx_registers[i]);
-			regval &= ~mask;
-			regval |= val;
-			writew(regval, pmx_registers[i]);
-		}
-	}
-}
-
-struct pmx *pmx_get(struct device *dev, enum pmx_settings setting)
-{
-	int i;
-	struct pmx *pmx = ERR_PTR(-ENOENT);
-
-	if (dev == NULL)
-		return ERR_PTR(-EINVAL);
-
-	mutex_lock(&pmx_mutex);
-	for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) {
-
-		if (setting == pmx_settings[i]->setting) {
-
-			if (pmx_settings[i]->dev != NULL) {
-				WARN(1, "padmux: required setting "
-				     "in use by another consumer\n");
-			} else {
-				pmx = pmx_settings[i];
-				pmx->dev = dev;
-				dev_dbg(dev, "padmux: setting nr %d is now "
-					"bound to %s and ready to use\n",
-					setting, dev_name(dev));
-				break;
-			}
-		}
-	}
-	mutex_unlock(&pmx_mutex);
-
-	return pmx;
-}
-EXPORT_SYMBOL(pmx_get);
-
-int pmx_put(struct device *dev, struct pmx *pmx)
-{
-	int i;
-	int ret = -ENOENT;
-
-	if (pmx == NULL || dev == NULL)
-		return -EINVAL;
-
-	mutex_lock(&pmx_mutex);
-	for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) {
-
-		if (pmx->setting == pmx_settings[i]->setting) {
-
-			if (dev != pmx->dev) {
-				WARN(1, "padmux: cannot release handle as "
-					"it is bound to another consumer\n");
-				ret = -EINVAL;
-				break;
-			} else {
-				pmx_settings[i]->dev = NULL;
-				ret = 0;
-				break;
-			}
-		}
-	}
-	mutex_unlock(&pmx_mutex);
-
-	return ret;
-}
-EXPORT_SYMBOL(pmx_put);
-
-int pmx_activate(struct device *dev, struct pmx *pmx)
-{
-	int i, j, ret;
-	ret = 0;
-
-	if (pmx == NULL || dev == NULL)
-		return -EINVAL;
-
-	mutex_lock(&pmx_mutex);
-
-	/* Make sure the required bits are not used */
-	for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) {
-
-		if (pmx_settings[i]->dev == NULL || pmx_settings[i] == pmx)
-			continue;
-
-		for (j = 0; j < ARRAY_SIZE(pmx_registers); j++) {
-
-			if (pmx_settings[i]->onmask[j].mask & pmx->
-				onmask[j].mask) {
-				/* More than one entry on the same bits */
-				WARN(1, "padmux: cannot activate "
-					"setting. Bit conflict with "
-					"an active setting\n");
-
-				ret = -EUSERS;
-				goto exit;
-			}
-		}
-	}
-	update_registers(pmx, true);
-	pmx->activated = true;
-	dev_dbg(dev, "padmux: setting nr %d is activated\n",
-		pmx->setting);
-
-exit:
-	mutex_unlock(&pmx_mutex);
-	return ret;
-}
-EXPORT_SYMBOL(pmx_activate);
-
-int pmx_deactivate(struct device *dev, struct pmx *pmx)
-{
-	int i;
-	int ret = -ENOENT;
-
-	if (pmx == NULL || dev == NULL)
-		return -EINVAL;
-
-	mutex_lock(&pmx_mutex);
-	for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) {
-
-		if (pmx_settings[i]->dev == NULL)
-			continue;
-
-		if (pmx->setting == pmx_settings[i]->setting) {
-
-			if (dev != pmx->dev) {
-				WARN(1, "padmux: cannot deactivate "
-				     "pmx setting as it was activated "
-				     "by another consumer\n");
-
-				ret = -EBUSY;
-				continue;
-			} else {
-				update_registers(pmx, false);
-				pmx_settings[i]->dev = NULL;
-				pmx->activated = false;
-				ret = 0;
-				dev_dbg(dev, "padmux: setting nr %d is deactivated",
-					pmx->setting);
-				break;
-			}
-		}
-	}
-	mutex_unlock(&pmx_mutex);
-
-	return ret;
-}
-EXPORT_SYMBOL(pmx_deactivate);
-
-/*
- * For internal use only. If it is to be exported,
- * it should be reentrant. Notice that pmx_activate
- * (i.e. runtime settings) always override default settings.
- */
-static int pmx_set_default(void)
-{
-	/* Used to identify several entries on the same bits */
-	u16 modbits[ARRAY_SIZE(pmx_registers)];
-
-	int i, j;
-
-	memset(modbits, 0, ARRAY_SIZE(pmx_registers) * sizeof(u16));
-
-	for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) {
-
-		if (!pmx_settings[i]->default_on)
-			continue;
-
-		for (j = 0; j < ARRAY_SIZE(pmx_registers); j++) {
-
-			/* Make sure there is only one entry on the same bits */
-			if (modbits[j] & pmx_settings[i]->onmask[j].mask) {
-				BUG();
-				return -EUSERS;
-			}
-			modbits[j] |= pmx_settings[i]->onmask[j].mask;
-		}
-		update_registers(pmx_settings[i], true);
-	}
-	return 0;
-}
-
-#if (defined(CONFIG_DEBUG_FS) && defined(CONFIG_U300_DEBUG))
-static int pmx_show(struct seq_file *s, void *data)
-{
-	int i;
-	seq_printf(s, "-------------------------------------------------\n");
-	seq_printf(s, "SETTING     BOUND TO DEVICE               STATE\n");
-	seq_printf(s, "-------------------------------------------------\n");
-	mutex_lock(&pmx_mutex);
-	for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) {
-		/* Format pmx and device name nicely */
-		char cdp[33];
-		int chars;
-
-		chars = snprintf(&cdp[0], 17, "%s", pmx_settings[i]->name);
-		while (chars < 16) {
-			cdp[chars] = ' ';
-			chars++;
-		}
-		chars = snprintf(&cdp[16], 17, "%s", pmx_settings[i]->dev ?
-				dev_name(pmx_settings[i]->dev) : "N/A");
-		while (chars < 16) {
-			cdp[chars+16] = ' ';
-			chars++;
-		}
-		cdp[32] = '\0';
-
-		seq_printf(s,
-			"%s\t%s\n",
-			&cdp[0],
-			pmx_settings[i]->activated ?
-			"ACTIVATED" : "DEACTIVATED"
-			);
-
-	}
-	mutex_unlock(&pmx_mutex);
-	return 0;
-}
-
-static int pmx_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, pmx_show, NULL);
-}
-
-static const struct file_operations pmx_operations = {
-	.owner		= THIS_MODULE,
-	.open		= pmx_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-static int __init init_pmx_read_debugfs(void)
-{
-	/* Expose a simple debugfs interface to view pmx settings */
-	(void) debugfs_create_file("padmux", S_IFREG | S_IRUGO,
-				   NULL, NULL,
-				   &pmx_operations);
-	return 0;
-}
-
-/*
- * This needs to come in after the core_initcall(),
- * because debugfs is not available until
- * the subsystems come up.
- */
-module_init(init_pmx_read_debugfs);
-#endif
-
-static int __init pmx_init(void)
-{
-	int ret;
-
-	ret = pmx_set_default();
-
-	if (IS_ERR_VALUE(ret))
-		pr_crit("padmux: default settings could not be set\n");
-
-	return 0;
-}
-
-/* Should be initialized before consumers */
-core_initcall(pmx_init);
diff --git a/arch/arm/mach-u300/padmux.h b/arch/arm/mach-u300/padmux.h
deleted file mode 100644
index 6e8b860..0000000
--- a/arch/arm/mach-u300/padmux.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- *
- * arch/arm/mach-u300/padmux.h
- *
- *
- * Copyright (C) 2009 ST-Ericsson AB
- * License terms: GNU General Public License (GPL) version 2
- * U300 PADMUX API
- * Author: Martin Persson <martin.persson@stericsson.com>
- */
-
-#ifndef __MACH_U300_PADMUX_H
-#define __MACH_U300_PADMUX_H
-
-enum pmx_settings {
-	U300_APP_PMX_MMC_SETTING,
-	U300_APP_PMX_SPI_SETTING
-};
-
-struct pmx_onmask {
-	u16 mask;		/* Mask bits */
-	u16 val;		/* Value when active */
-};
-
-struct pmx {
-	struct device *dev;
-	enum pmx_settings setting;
-	char *name;
-	bool activated;
-	bool default_on;
-	struct pmx_onmask onmask[];
-};
-
-struct pmx *pmx_get(struct device *dev, enum pmx_settings setting);
-int pmx_put(struct device *dev, struct pmx *pmx);
-int pmx_activate(struct device *dev, struct pmx *pmx);
-int pmx_deactivate(struct device *dev, struct pmx *pmx);
-
-#endif
diff --git a/arch/arm/mach-u300/spi.c b/arch/arm/mach-u300/spi.c
index 7b597e2..a1affac 100644
--- a/arch/arm/mach-u300/spi.c
+++ b/arch/arm/mach-u300/spi.c
@@ -14,8 +14,6 @@
 #include <mach/coh901318.h>
 #include <mach/dma_channels.h>
 
-#include "padmux.h"
-
 /*
  * The following is for the actual devices on the SSP/SPI bus
  */
@@ -95,25 +93,7 @@ static struct pl022_ssp_controller ssp_platform_data = {
 
 void __init u300_spi_init(struct amba_device *adev)
 {
-	struct pmx *pmx;
-
 	adev->dev.platform_data = &ssp_platform_data;
-	/*
-	 * Setup padmuxing for SPI. Since this must always be
-	 * compiled into the kernel, pmx is never released.
-	 */
-	pmx = pmx_get(&adev->dev, U300_APP_PMX_SPI_SETTING);
-
-	if (IS_ERR(pmx))
-		dev_warn(&adev->dev, "Could not get padmux handle\n");
-	else {
-		int ret;
-
-		ret = pmx_activate(&adev->dev, pmx);
-		if (IS_ERR_VALUE(ret))
-			dev_warn(&adev->dev, "Could not activate padmuxing\n");
-	}
-
 }
 
 void __init u300_spi_register_board_devices(void)
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 7fa0fe0..8b3d081 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -26,4 +26,11 @@ config DEBUG_PINCTRL
 	help
 	  Say Y here to add some extra checks and diagnostics to PINCTRL calls.
 
+config PINMUX_U300
+	bool "U300 pinmux driver"
+	depends on ARCH_U300
+	select PINMUX
+	help
+	  Say Y here to enable the U300 pinmux driver
+
 endif
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 596ce9f..63d4241 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -4,3 +4,4 @@ ccflags-$(CONFIG_DEBUG_PINMUX)	+= -DDEBUG
 
 obj-$(CONFIG_PINCTRL)		+= core.o
 obj-$(CONFIG_PINMUX)		+= pinmux.o
+obj-$(CONFIG_PINMUX_U300)	+= pinmux-u300.o
diff --git a/drivers/pinctrl/pinmux-u300.c b/drivers/pinctrl/pinmux-u300.c
new file mode 100644
index 0000000..a5c3385
--- /dev/null
+++ b/drivers/pinctrl/pinmux-u300.c
@@ -0,0 +1,1148 @@
+/*
+ * Driver for the U300 pin controller
+ *
+ * Based on the original U300 padmux functions
+ * Copyright (C) 2009-2011 ST-Ericsson AB
+ * Author: Martin Persson <martin.persson@stericsson.com>
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * The DB3350 design and control registers are oriented around pads rather than
+ * pins, so we enumerate the pads we can mux rather than actual pins. The pads
+ * are connected to different pins in different packaging types, so it would
+ * be confusing.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+
+/*
+ * Register definitions for the U300 Padmux control registers in the
+ * system controller
+ */
+
+/* PAD MUX Control register 1 (LOW) 16bit (R/W) */
+#define U300_SYSCON_PMC1LR					0x007C
+#define U300_SYSCON_PMC1LR_MASK					0xFFFF
+#define U300_SYSCON_PMC1LR_CDI_MASK				0xC000
+#define U300_SYSCON_PMC1LR_CDI_CDI				0x0000
+#define U300_SYSCON_PMC1LR_CDI_EMIF				0x4000
+/* For BS335 */
+#define U300_SYSCON_PMC1LR_CDI_CDI2				0x8000
+#define U300_SYSCON_PMC1LR_CDI_WCDMA_APP_GPIO			0xC000
+/* For BS365 */
+#define U300_SYSCON_PMC1LR_CDI_GPIO				0x8000
+#define U300_SYSCON_PMC1LR_CDI_WCDMA				0xC000
+/* Common defs */
+#define U300_SYSCON_PMC1LR_PDI_MASK				0x3000
+#define U300_SYSCON_PMC1LR_PDI_PDI				0x0000
+#define U300_SYSCON_PMC1LR_PDI_EGG				0x1000
+#define U300_SYSCON_PMC1LR_PDI_WCDMA				0x3000
+#define U300_SYSCON_PMC1LR_MMCSD_MASK				0x0C00
+#define U300_SYSCON_PMC1LR_MMCSD_MMCSD				0x0000
+#define U300_SYSCON_PMC1LR_MMCSD_MSPRO				0x0400
+#define U300_SYSCON_PMC1LR_MMCSD_DSP				0x0800
+#define U300_SYSCON_PMC1LR_MMCSD_WCDMA				0x0C00
+#define U300_SYSCON_PMC1LR_ETM_MASK				0x0300
+#define U300_SYSCON_PMC1LR_ETM_ACC				0x0000
+#define U300_SYSCON_PMC1LR_ETM_APP				0x0100
+#define U300_SYSCON_PMC1LR_EMIF_1_CS2_MASK			0x00C0
+#define U300_SYSCON_PMC1LR_EMIF_1_CS2_STATIC			0x0000
+#define U300_SYSCON_PMC1LR_EMIF_1_CS2_NFIF			0x0040
+#define U300_SYSCON_PMC1LR_EMIF_1_CS2_SDRAM			0x0080
+#define U300_SYSCON_PMC1LR_EMIF_1_CS2_STATIC_2GB		0x00C0
+#define U300_SYSCON_PMC1LR_EMIF_1_CS1_MASK			0x0030
+#define U300_SYSCON_PMC1LR_EMIF_1_CS1_STATIC			0x0000
+#define U300_SYSCON_PMC1LR_EMIF_1_CS1_NFIF			0x0010
+#define U300_SYSCON_PMC1LR_EMIF_1_CS1_SDRAM			0x0020
+#define U300_SYSCON_PMC1LR_EMIF_1_CS1_SEMI			0x0030
+#define U300_SYSCON_PMC1LR_EMIF_1_CS0_MASK			0x000C
+#define U300_SYSCON_PMC1LR_EMIF_1_CS0_STATIC			0x0000
+#define U300_SYSCON_PMC1LR_EMIF_1_CS0_NFIF			0x0004
+#define U300_SYSCON_PMC1LR_EMIF_1_CS0_SDRAM			0x0008
+#define U300_SYSCON_PMC1LR_EMIF_1_CS0_SEMI			0x000C
+#define U300_SYSCON_PMC1LR_EMIF_1_MASK				0x0003
+#define U300_SYSCON_PMC1LR_EMIF_1_STATIC			0x0000
+#define U300_SYSCON_PMC1LR_EMIF_1_SDRAM0			0x0001
+#define U300_SYSCON_PMC1LR_EMIF_1_SDRAM1			0x0002
+#define U300_SYSCON_PMC1LR_EMIF_1				0x0003
+/* PAD MUX Control register 2 (HIGH) 16bit (R/W) */
+#define U300_SYSCON_PMC1HR					0x007E
+#define U300_SYSCON_PMC1HR_MASK					0xFFFF
+#define U300_SYSCON_PMC1HR_MISC_2_MASK				0xC000
+#define U300_SYSCON_PMC1HR_MISC_2_APP_GPIO			0x0000
+#define U300_SYSCON_PMC1HR_MISC_2_MSPRO				0x4000
+#define U300_SYSCON_PMC1HR_MISC_2_DSP				0x8000
+#define U300_SYSCON_PMC1HR_MISC_2_AAIF				0xC000
+#define U300_SYSCON_PMC1HR_APP_GPIO_2_MASK			0x3000
+#define U300_SYSCON_PMC1HR_APP_GPIO_2_APP_GPIO			0x0000
+#define U300_SYSCON_PMC1HR_APP_GPIO_2_NFIF			0x1000
+#define U300_SYSCON_PMC1HR_APP_GPIO_2_DSP			0x2000
+#define U300_SYSCON_PMC1HR_APP_GPIO_2_AAIF			0x3000
+#define U300_SYSCON_PMC1HR_APP_GPIO_1_MASK			0x0C00
+#define U300_SYSCON_PMC1HR_APP_GPIO_1_APP_GPIO			0x0000
+#define U300_SYSCON_PMC1HR_APP_GPIO_1_MMC			0x0400
+#define U300_SYSCON_PMC1HR_APP_GPIO_1_DSP			0x0800
+#define U300_SYSCON_PMC1HR_APP_GPIO_1_AAIF			0x0C00
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_2_MASK			0x0300
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_2_APP_GPIO		0x0000
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_2_SPI			0x0100
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_2_AAIF			0x0300
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_1_MASK			0x00C0
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_1_APP_GPIO		0x0000
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_1_SPI			0x0040
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_1_AAIF			0x00C0
+#define U300_SYSCON_PMC1HR_APP_SPI_2_MASK			0x0030
+#define U300_SYSCON_PMC1HR_APP_SPI_2_APP_GPIO			0x0000
+#define U300_SYSCON_PMC1HR_APP_SPI_2_SPI			0x0010
+#define U300_SYSCON_PMC1HR_APP_SPI_2_DSP			0x0020
+#define U300_SYSCON_PMC1HR_APP_SPI_2_AAIF			0x0030
+#define U300_SYSCON_PMC1HR_APP_UART0_2_MASK			0x000C
+#define U300_SYSCON_PMC1HR_APP_UART0_2_APP_GPIO			0x0000
+#define U300_SYSCON_PMC1HR_APP_UART0_2_UART0			0x0004
+#define U300_SYSCON_PMC1HR_APP_UART0_2_NFIF_CS			0x0008
+#define U300_SYSCON_PMC1HR_APP_UART0_2_AAIF			0x000C
+#define U300_SYSCON_PMC1HR_APP_UART0_1_MASK			0x0003
+#define U300_SYSCON_PMC1HR_APP_UART0_1_APP_GPIO			0x0000
+#define U300_SYSCON_PMC1HR_APP_UART0_1_UART0			0x0001
+#define U300_SYSCON_PMC1HR_APP_UART0_1_AAIF			0x0003
+/* Padmux 2 control */
+#define U300_SYSCON_PMC2R					0x100
+#define U300_SYSCON_PMC2R_APP_MISC_0_MASK			0x00C0
+#define U300_SYSCON_PMC2R_APP_MISC_0_APP_GPIO			0x0000
+#define U300_SYSCON_PMC2R_APP_MISC_0_EMIF_SDRAM			0x0040
+#define U300_SYSCON_PMC2R_APP_MISC_0_MMC			0x0080
+#define U300_SYSCON_PMC2R_APP_MISC_0_CDI2			0x00C0
+#define U300_SYSCON_PMC2R_APP_MISC_1_MASK			0x0300
+#define U300_SYSCON_PMC2R_APP_MISC_1_APP_GPIO			0x0000
+#define U300_SYSCON_PMC2R_APP_MISC_1_EMIF_SDRAM			0x0100
+#define U300_SYSCON_PMC2R_APP_MISC_1_MMC			0x0200
+#define U300_SYSCON_PMC2R_APP_MISC_1_CDI2			0x0300
+#define U300_SYSCON_PMC2R_APP_MISC_2_MASK			0x0C00
+#define U300_SYSCON_PMC2R_APP_MISC_2_APP_GPIO			0x0000
+#define U300_SYSCON_PMC2R_APP_MISC_2_EMIF_SDRAM			0x0400
+#define U300_SYSCON_PMC2R_APP_MISC_2_MMC			0x0800
+#define U300_SYSCON_PMC2R_APP_MISC_2_CDI2			0x0C00
+#define U300_SYSCON_PMC2R_APP_MISC_3_MASK			0x3000
+#define U300_SYSCON_PMC2R_APP_MISC_3_APP_GPIO			0x0000
+#define U300_SYSCON_PMC2R_APP_MISC_3_EMIF_SDRAM			0x1000
+#define U300_SYSCON_PMC2R_APP_MISC_3_MMC			0x2000
+#define U300_SYSCON_PMC2R_APP_MISC_3_CDI2			0x3000
+#define U300_SYSCON_PMC2R_APP_MISC_4_MASK			0xC000
+#define U300_SYSCON_PMC2R_APP_MISC_4_APP_GPIO			0x0000
+#define U300_SYSCON_PMC2R_APP_MISC_4_EMIF_SDRAM			0x4000
+#define U300_SYSCON_PMC2R_APP_MISC_4_MMC			0x8000
+#define U300_SYSCON_PMC2R_APP_MISC_4_ACC_GPIO			0xC000
+/* TODO: More SYSCON registers missing */
+#define U300_SYSCON_PMC3R					0x10C
+#define U300_SYSCON_PMC3R_APP_MISC_11_MASK			0xC000
+#define U300_SYSCON_PMC3R_APP_MISC_11_SPI			0x4000
+#define U300_SYSCON_PMC3R_APP_MISC_10_MASK			0x3000
+#define U300_SYSCON_PMC3R_APP_MISC_10_SPI			0x1000
+/* TODO: Missing other configs */
+#define U300_SYSCON_PMC4R					0x168
+#define U300_SYSCON_PMC4R_APP_MISC_12_MASK			0x0003
+#define U300_SYSCON_PMC4R_APP_MISC_12_APP_GPIO			0x0000
+#define U300_SYSCON_PMC4R_APP_MISC_13_MASK			0x000C
+#define U300_SYSCON_PMC4R_APP_MISC_13_CDI			0x0000
+#define U300_SYSCON_PMC4R_APP_MISC_13_SMIA			0x0004
+#define U300_SYSCON_PMC4R_APP_MISC_13_SMIA2			0x0008
+#define U300_SYSCON_PMC4R_APP_MISC_13_APP_GPIO			0x000C
+#define U300_SYSCON_PMC4R_APP_MISC_14_MASK			0x0030
+#define U300_SYSCON_PMC4R_APP_MISC_14_CDI			0x0000
+#define U300_SYSCON_PMC4R_APP_MISC_14_SMIA			0x0010
+#define U300_SYSCON_PMC4R_APP_MISC_14_CDI2			0x0020
+#define U300_SYSCON_PMC4R_APP_MISC_14_APP_GPIO			0x0030
+#define U300_SYSCON_PMC4R_APP_MISC_16_MASK			0x0300
+#define U300_SYSCON_PMC4R_APP_MISC_16_APP_GPIO_13		0x0000
+#define U300_SYSCON_PMC4R_APP_MISC_16_APP_UART1_CTS		0x0100
+#define U300_SYSCON_PMC4R_APP_MISC_16_EMIF_1_STATIC_CS5_N	0x0200
+
+#define DRIVER_NAME "pinmux-u300"
+
+/*
+ * The DB3350 has 467 pads, I have enumerated the pads clockwise around the
+ * edges of the silicon, finger by finger. LTCORNER upper left is pad 0.
+ * Data taken from the PadRing chart, arranged like this:
+ *
+ *   0 ..... 104
+ * 466        105
+ *   .        .
+ *   .        .
+ * 358        224
+ *  357 .... 225
+ */
+#define U300_NUM_PADS 467
+
+/* Pad names for the pinmux subsystem */
+static const struct pinctrl_pin_desc __refdata u300_pads[] = {
+	/* Pads along the top edge of the chip */
+	PINCTRL_PIN(0, "P PAD VDD 28"),
+	PINCTRL_PIN(1, "P PAD GND 28"),
+	PINCTRL_PIN(2, "PO SIM RST N"),
+	PINCTRL_PIN(3, "VSSIO 25"),
+	PINCTRL_PIN(4, "VSSA ADDA ESDSUB"),
+	PINCTRL_PIN(5, "PWR VSSCOMMON"),
+	PINCTRL_PIN(6, "PI ADC I1 POS"),
+	PINCTRL_PIN(7, "PI ADC I1 NEG"),
+	PINCTRL_PIN(8, "PWR VSSAD0"),
+	PINCTRL_PIN(9, "PWR VCCAD0"),
+	PINCTRL_PIN(10, "PI ADC Q1 NEG"),
+	PINCTRL_PIN(11, "PI ADC Q1 POS"),
+	PINCTRL_PIN(12, "PWR VDDAD"),
+	PINCTRL_PIN(13, "PWR GNDAD"),
+	PINCTRL_PIN(14, "PI ADC I2 POS"),
+	PINCTRL_PIN(15, "PI ADC I2 NEG"),
+	PINCTRL_PIN(16, "PWR VSSAD1"),
+	PINCTRL_PIN(17, "PWR VCCAD1"),
+	PINCTRL_PIN(18, "PI ADC Q2 NEG"),
+	PINCTRL_PIN(19, "PI ADC Q2 POS"),
+	PINCTRL_PIN(20, "VSSA ADDA ESDSUB"),
+	PINCTRL_PIN(21, "PWR VCCGPAD"),
+	PINCTRL_PIN(22, "PI TX POW"),
+	PINCTRL_PIN(23, "PWR VSSGPAD"),
+	PINCTRL_PIN(24, "PO DAC I POS"),
+	PINCTRL_PIN(25, "PO DAC I NEG"),
+	PINCTRL_PIN(26, "PO DAC Q POS"),
+	PINCTRL_PIN(27, "PO DAC Q NEG"),
+	PINCTRL_PIN(28, "PWR VSSDA"),
+	PINCTRL_PIN(29, "PWR VCCDA"),
+	PINCTRL_PIN(30, "VSSA ADDA ESDSUB"),
+	PINCTRL_PIN(31, "P PAD VDDIO 11"),
+	PINCTRL_PIN(32, "PI PLL 26 FILTVDD"),
+	PINCTRL_PIN(33, "PI PLL 26 VCONT"),
+	PINCTRL_PIN(34, "PWR AGNDPLL2V5 32 13"),
+	PINCTRL_PIN(35, "PWR AVDDPLL2V5 32 13"),
+	PINCTRL_PIN(36, "VDDA PLL ESD"),
+	PINCTRL_PIN(37, "VSSA PLL ESD"),
+	PINCTRL_PIN(38, "VSS PLL"),
+	PINCTRL_PIN(39, "VDDC PLL"),
+	PINCTRL_PIN(40, "PWR AGNDPLL2V5 26 60"),
+	PINCTRL_PIN(41, "PWR AVDDPLL2V5 26 60"),
+	PINCTRL_PIN(42, "PWR AVDDPLL2V5 26 208"),
+	PINCTRL_PIN(43, "PWR AGNDPLL2V5 26 208"),
+	PINCTRL_PIN(44, "PWR AVDDPLL2V5 13 208"),
+	PINCTRL_PIN(45, "PWR AGNDPLL2V5 13 208"),
+	PINCTRL_PIN(46, "P PAD VSSIO 11"),
+	PINCTRL_PIN(47, "P PAD VSSIO 12"),
+	PINCTRL_PIN(48, "PI POW RST N"),
+	PINCTRL_PIN(49, "VDDC IO"),
+	PINCTRL_PIN(50, "P PAD VDDIO 16"),
+	PINCTRL_PIN(51, "PO RF WCDMA EN 4"),
+	PINCTRL_PIN(52, "PO RF WCDMA EN 3"),
+	PINCTRL_PIN(53, "PO RF WCDMA EN 2"),
+	PINCTRL_PIN(54, "PO RF WCDMA EN 1"),
+	PINCTRL_PIN(55, "PO RF WCDMA EN 0"),
+	PINCTRL_PIN(56, "PO GSM PA ENABLE"),
+	PINCTRL_PIN(57, "PO RF DATA STRB"),
+	PINCTRL_PIN(58, "PO RF DATA2"),
+	PINCTRL_PIN(59, "PIO RF DATA1"),
+	PINCTRL_PIN(60, "PIO RF DATA0"),
+	PINCTRL_PIN(61, "P PAD VDD 11"),
+	PINCTRL_PIN(62, "P PAD GND 11"),
+	PINCTRL_PIN(63, "P PAD VSSIO 16"),
+	PINCTRL_PIN(64, "P PAD VDDIO 18"),
+	PINCTRL_PIN(65, "PO RF CTRL STRB2"),
+	PINCTRL_PIN(66, "PO RF CTRL STRB1"),
+	PINCTRL_PIN(67, "PO RF CTRL STRB0"),
+	PINCTRL_PIN(68, "PIO RF CTRL DATA"),
+	PINCTRL_PIN(69, "PO RF CTRL CLK"),
+	PINCTRL_PIN(70, "PO TX ADC STRB"),
+	PINCTRL_PIN(71, "PO ANT SW 2"),
+	PINCTRL_PIN(72, "PO ANT SW 3"),
+	PINCTRL_PIN(73, "PO ANT SW 0"),
+	PINCTRL_PIN(74, "PO ANT SW 1"),
+	PINCTRL_PIN(75, "PO M CLKRQ"),
+	PINCTRL_PIN(76, "PI M CLK"),
+	PINCTRL_PIN(77, "PI RTC CLK"),
+	PINCTRL_PIN(78, "P PAD VDD 8"),
+	PINCTRL_PIN(79, "P PAD GND 8"),
+	PINCTRL_PIN(80, "P PAD VSSIO 13"),
+	PINCTRL_PIN(81, "P PAD VDDIO 13"),
+	PINCTRL_PIN(82, "PO SYS 1 CLK"),
+	PINCTRL_PIN(83, "PO SYS 2 CLK"),
+	PINCTRL_PIN(84, "PO SYS 0 CLK"),
+	PINCTRL_PIN(85, "PI SYS 0 CLKRQ"),
+	PINCTRL_PIN(86, "PO PWR MNGT CTRL 1"),
+	PINCTRL_PIN(87, "PO PWR MNGT CTRL 0"),
+	PINCTRL_PIN(88, "PO RESOUT2 RST N"),
+	PINCTRL_PIN(89, "PO RESOUT1 RST N"),
+	PINCTRL_PIN(90, "PO RESOUT0 RST N"),
+	PINCTRL_PIN(91, "PI SERVICE N"),
+	PINCTRL_PIN(92, "P PAD VDD 29"),
+	PINCTRL_PIN(93, "P PAD GND 29"),
+	PINCTRL_PIN(94, "P PAD VSSIO 8"),
+	PINCTRL_PIN(95, "P PAD VDDIO 8"),
+	PINCTRL_PIN(96, "PI EXT IRQ1 N"),
+	PINCTRL_PIN(97, "PI EXT IRQ0 N"),
+	PINCTRL_PIN(98, "PIO DC ON"),
+	PINCTRL_PIN(99, "PIO ACC APP I2C DATA"),
+	PINCTRL_PIN(100, "PIO ACC APP I2C CLK"),
+	PINCTRL_PIN(101, "P PAD VDD 12"),
+	PINCTRL_PIN(102, "P PAD GND 12"),
+	PINCTRL_PIN(103, "P PAD VSSIO 14"),
+	PINCTRL_PIN(104, "P PAD VDDIO 14"),
+	/* Pads along the right edge of the chip */
+	PINCTRL_PIN(105, "PIO APP I2C1 DATA"),
+	PINCTRL_PIN(106, "PIO APP I2C1 CLK"),
+	PINCTRL_PIN(107, "PO KEY OUT0"),
+	PINCTRL_PIN(108, "PO KEY OUT1"),
+	PINCTRL_PIN(109, "PO KEY OUT2"),
+	PINCTRL_PIN(110, "PO KEY OUT3"),
+	PINCTRL_PIN(111, "PO KEY OUT4"),
+	PINCTRL_PIN(112, "PI KEY IN0"),
+	PINCTRL_PIN(113, "PI KEY IN1"),
+	PINCTRL_PIN(114, "PI KEY IN2"),
+	PINCTRL_PIN(115, "P PAD VDDIO 15"),
+	PINCTRL_PIN(116, "P PAD VSSIO 15"),
+	PINCTRL_PIN(117, "P PAD GND 13"),
+	PINCTRL_PIN(118, "P PAD VDD 13"),
+	PINCTRL_PIN(119, "PI KEY IN3"),
+	PINCTRL_PIN(120, "PI KEY IN4"),
+	PINCTRL_PIN(121, "PI KEY IN5"),
+	PINCTRL_PIN(122, "PIO APP PCM I2S1 DATA B"),
+	PINCTRL_PIN(123, "PIO APP PCM I2S1 DATA A"),
+	PINCTRL_PIN(124, "PIO APP PCM I2S1 WS"),
+	PINCTRL_PIN(125, "PIO APP PCM I2S1 CLK"),
+	PINCTRL_PIN(126, "PIO APP PCM I2S0 DATA B"),
+	PINCTRL_PIN(127, "PIO APP PCM I2S0 DATA A"),
+	PINCTRL_PIN(128, "PIO APP PCM I2S0 WS"),
+	PINCTRL_PIN(129, "PIO APP PCM I2S0 CLK"),
+	PINCTRL_PIN(130, "P PAD VDD 17"),
+	PINCTRL_PIN(131, "P PAD GND 17"),
+	PINCTRL_PIN(132, "P PAD VSSIO 19"),
+	PINCTRL_PIN(133, "P PAD VDDIO 19"),
+	PINCTRL_PIN(134, "UART0 RTS"),
+	PINCTRL_PIN(135, "UART0 CTS"),
+	PINCTRL_PIN(136, "UART0 TX"),
+	PINCTRL_PIN(137, "UART0 RX"),
+	PINCTRL_PIN(138, "PIO ACC SPI DO"),
+	PINCTRL_PIN(139, "PIO ACC SPI DI"),
+	PINCTRL_PIN(140, "PIO ACC SPI CS0 N"),
+	PINCTRL_PIN(141, "PIO ACC SPI CS1 N"),
+	PINCTRL_PIN(142, "PIO ACC SPI CS2 N"),
+	PINCTRL_PIN(143, "PIO ACC SPI CLK"),
+	PINCTRL_PIN(144, "PO PDI EXT RST N"),
+	PINCTRL_PIN(145, "P PAD VDDIO 22"),
+	PINCTRL_PIN(146, "P PAD VSSIO 22"),
+	PINCTRL_PIN(147, "P PAD GND 18"),
+	PINCTRL_PIN(148, "P PAD VDD 18"),
+	PINCTRL_PIN(149, "PIO PDI C0"),
+	PINCTRL_PIN(150, "PIO PDI C1"),
+	PINCTRL_PIN(151, "PIO PDI C2"),
+	PINCTRL_PIN(152, "PIO PDI C3"),
+	PINCTRL_PIN(153, "PIO PDI C4"),
+	PINCTRL_PIN(154, "PIO PDI C5"),
+	PINCTRL_PIN(155, "PIO PDI D0"),
+	PINCTRL_PIN(156, "PIO PDI D1"),
+	PINCTRL_PIN(157, "PIO PDI D2"),
+	PINCTRL_PIN(158, "PIO PDI D3"),
+	PINCTRL_PIN(159, "P PAD VDDIO 21"),
+	PINCTRL_PIN(160, "P PAD VSSIO 21"),
+	PINCTRL_PIN(161, "PIO PDI D4"),
+	PINCTRL_PIN(162, "PIO PDI D5"),
+	PINCTRL_PIN(163, "PIO PDI D6"),
+	PINCTRL_PIN(164, "PIO PDI D7"),
+	PINCTRL_PIN(165, "PIO MS INS"),
+	PINCTRL_PIN(166, "MMC DATA DIR LS"),
+	PINCTRL_PIN(167, "MMC DATA 3"),
+	PINCTRL_PIN(168, "MMC DATA 2"),
+	PINCTRL_PIN(169, "MMC DATA 1"),
+	PINCTRL_PIN(170, "MMC DATA 0"),
+	PINCTRL_PIN(171, "MMC CMD DIR LS"),
+	PINCTRL_PIN(172, "P PAD VDD 27"),
+	PINCTRL_PIN(173, "P PAD GND 27"),
+	PINCTRL_PIN(174, "P PAD VSSIO 20"),
+	PINCTRL_PIN(175, "P PAD VDDIO 20"),
+	PINCTRL_PIN(176, "MMC CMD"),
+	PINCTRL_PIN(177, "MMC CLK"),
+	PINCTRL_PIN(178, "PIO APP GPIO 14"),
+	PINCTRL_PIN(179, "PIO APP GPIO 13"),
+	PINCTRL_PIN(180, "PIO APP GPIO 11"),
+	PINCTRL_PIN(181, "PIO APP GPIO 25"),
+	PINCTRL_PIN(182, "PIO APP GPIO 24"),
+	PINCTRL_PIN(183, "PIO APP GPIO 23"),
+	PINCTRL_PIN(184, "PIO APP GPIO 22"),
+	PINCTRL_PIN(185, "PIO APP GPIO 21"),
+	PINCTRL_PIN(186, "PIO APP GPIO 20"),
+	PINCTRL_PIN(187, "P PAD VDD 19"),
+	PINCTRL_PIN(188, "P PAD GND 19"),
+	PINCTRL_PIN(189, "P PAD VSSIO 23"),
+	PINCTRL_PIN(190, "P PAD VDDIO 23"),
+	PINCTRL_PIN(191, "PIO APP GPIO 19"),
+	PINCTRL_PIN(192, "PIO APP GPIO 18"),
+	PINCTRL_PIN(193, "PIO APP GPIO 17"),
+	PINCTRL_PIN(194, "PIO APP GPIO 16"),
+	PINCTRL_PIN(195, "PI CI D1"),
+	PINCTRL_PIN(196, "PI CI D0"),
+	PINCTRL_PIN(197, "PI CI HSYNC"),
+	PINCTRL_PIN(198, "PI CI VSYNC"),
+	PINCTRL_PIN(199, "PI CI EXT CLK"),
+	PINCTRL_PIN(200, "PO CI EXT RST N"),
+	PINCTRL_PIN(201, "P PAD VSSIO 43"),
+	PINCTRL_PIN(202, "P PAD VDDIO 43"),
+	PINCTRL_PIN(203, "PI CI D6"),
+	PINCTRL_PIN(204, "PI CI D7"),
+	PINCTRL_PIN(205, "PI CI D2"),
+	PINCTRL_PIN(206, "PI CI D3"),
+	PINCTRL_PIN(207, "PI CI D4"),
+	PINCTRL_PIN(208, "PI CI D5"),
+	PINCTRL_PIN(209, "PI CI D8"),
+	PINCTRL_PIN(210, "PI CI D9"),
+	PINCTRL_PIN(211, "P PAD VDD 20"),
+	PINCTRL_PIN(212, "P PAD GND 20"),
+	PINCTRL_PIN(213, "P PAD VSSIO 24"),
+	PINCTRL_PIN(214, "P PAD VDDIO 24"),
+	PINCTRL_PIN(215, "P PAD VDDIO 26"),
+	PINCTRL_PIN(216, "PO EMIF 1 A26"),
+	PINCTRL_PIN(217, "PO EMIF 1 A25"),
+	PINCTRL_PIN(218, "P PAD VSSIO 26"),
+	PINCTRL_PIN(219, "PO EMIF 1 A24"),
+	PINCTRL_PIN(220, "PO EMIF 1 A23"),
+	/* Pads along the bottom edge of the chip */
+	PINCTRL_PIN(221, "PO EMIF 1 A22"),
+	PINCTRL_PIN(222, "PO EMIF 1 A21"),
+	PINCTRL_PIN(223, "P PAD VDD 21"),
+	PINCTRL_PIN(224, "P PAD GND 21"),
+	PINCTRL_PIN(225, "P PAD VSSIO 27"),
+	PINCTRL_PIN(226, "P PAD VDDIO 27"),
+	PINCTRL_PIN(227, "PO EMIF 1 A20"),
+	PINCTRL_PIN(228, "PO EMIF 1 A19"),
+	PINCTRL_PIN(229, "PO EMIF 1 A18"),
+	PINCTRL_PIN(230, "PO EMIF 1 A17"),
+	PINCTRL_PIN(231, "P PAD VDDIO 28"),
+	PINCTRL_PIN(232, "P PAD VSSIO 28"),
+	PINCTRL_PIN(233, "PO EMIF 1 A16"),
+	PINCTRL_PIN(234, "PIO EMIF 1 D15"),
+	PINCTRL_PIN(235, "PO EMIF 1 A15"),
+	PINCTRL_PIN(236, "PIO EMIF 1 D14"),
+	PINCTRL_PIN(237, "P PAD VDD 22"),
+	PINCTRL_PIN(238, "P PAD GND 22"),
+	PINCTRL_PIN(239, "P PAD VSSIO 29"),
+	PINCTRL_PIN(240, "P PAD VDDIO 29"),
+	PINCTRL_PIN(241, "PO EMIF 1 A14"),
+	PINCTRL_PIN(242, "PIO EMIF 1 D13"),
+	PINCTRL_PIN(243, "PO EMIF 1 A13"),
+	PINCTRL_PIN(244, "PIO EMIF 1 D12"),
+	PINCTRL_PIN(245, "P PAD VSSIO 30"),
+	PINCTRL_PIN(246, "P PAD VDDIO 30"),
+	PINCTRL_PIN(247, "PO EMIF 1 A12"),
+	PINCTRL_PIN(248, "PIO EMIF 1 D11"),
+	PINCTRL_PIN(249, "PO EMIF 1 A11"),
+	PINCTRL_PIN(250, "PIO EMIF 1 D10"),
+	PINCTRL_PIN(251, "P PAD VSSIO 31"),
+	PINCTRL_PIN(252, "P PAD VDDIO 31"),
+	PINCTRL_PIN(253, "PO EMIF 1 A10"),
+	PINCTRL_PIN(254, "PIO EMIF 1 D09"),
+	PINCTRL_PIN(255, "PO EMIF 1 A09"),
+	PINCTRL_PIN(256, "P PAD VDDIO 32"),
+	PINCTRL_PIN(257, "P PAD VSSIO 32"),
+	PINCTRL_PIN(258, "P PAD GND 24"),
+	PINCTRL_PIN(259, "P PAD VDD 24"),
+	PINCTRL_PIN(260, "PIO EMIF 1 D08"),
+	PINCTRL_PIN(261, "PO EMIF 1 A08"),
+	PINCTRL_PIN(262, "PIO EMIF 1 D07"),
+	PINCTRL_PIN(263, "PO EMIF 1 A07"),
+	PINCTRL_PIN(264, "P PAD VDDIO 33"),
+	PINCTRL_PIN(265, "P PAD VSSIO 33"),
+	PINCTRL_PIN(266, "PIO EMIF 1 D06"),
+	PINCTRL_PIN(267, "PO EMIF 1 A06"),
+	PINCTRL_PIN(268, "PIO EMIF 1 D05"),
+	PINCTRL_PIN(269, "PO EMIF 1 A05"),
+	PINCTRL_PIN(270, "P PAD VDDIO 34"),
+	PINCTRL_PIN(271, "P PAD VSSIO 34"),
+	PINCTRL_PIN(272, "PIO EMIF 1 D04"),
+	PINCTRL_PIN(273, "PO EMIF 1 A04"),
+	PINCTRL_PIN(274, "PIO EMIF 1 D03"),
+	PINCTRL_PIN(275, "PO EMIF 1 A03"),
+	PINCTRL_PIN(276, "P PAD VDDIO 35"),
+	PINCTRL_PIN(277, "P PAD VSSIO 35"),
+	PINCTRL_PIN(278, "P PAD GND 23"),
+	PINCTRL_PIN(279, "P PAD VDD 23"),
+	PINCTRL_PIN(280, "PIO EMIF 1 D02"),
+	PINCTRL_PIN(281, "PO EMIF 1 A02"),
+	PINCTRL_PIN(282, "PIO EMIF 1 D01"),
+	PINCTRL_PIN(283, "PO EMIF 1 A01"),
+	PINCTRL_PIN(284, "P PAD VDDIO 36"),
+	PINCTRL_PIN(285, "P PAD VSSIO 36"),
+	PINCTRL_PIN(286, "PIO EMIF 1 D00"),
+	PINCTRL_PIN(287, "PO EMIF 1 BE1 N"),
+	PINCTRL_PIN(288, "PO EMIF 1 BE0 N"),
+	PINCTRL_PIN(289, "PO EMIF 1 ADV N"),
+	PINCTRL_PIN(290, "P PAD VDDIO 37"),
+	PINCTRL_PIN(291, "P PAD VSSIO 37"),
+	PINCTRL_PIN(292, "PO EMIF 1 SD CKE0"),
+	PINCTRL_PIN(293, "PO EMIF 1 OE N"),
+	PINCTRL_PIN(294, "PO EMIF 1 WE N"),
+	PINCTRL_PIN(295, "P PAD VDDIO 38"),
+	PINCTRL_PIN(296, "P PAD VSSIO 38"),
+	PINCTRL_PIN(297, "PO EMIF 1 CLK"),
+	PINCTRL_PIN(298, "PIO EMIF 1 SD CLK"),
+	PINCTRL_PIN(299, "P PAD VSSIO 45 (not bonded)"),
+	PINCTRL_PIN(300, "P PAD VDDIO 42"),
+	PINCTRL_PIN(301, "P PAD VSSIO 42"),
+	PINCTRL_PIN(302, "P PAD GND 31"),
+	PINCTRL_PIN(303, "P PAD VDD 31"),
+	PINCTRL_PIN(304, "PI EMIF 1 RET CLK"),
+	PINCTRL_PIN(305, "PI EMIF 1 WAIT N"),
+	PINCTRL_PIN(306, "PI EMIF 1 NFIF READY"),
+	PINCTRL_PIN(307, "PO EMIF 1 SD CKE1"),
+	PINCTRL_PIN(308, "PO EMIF 1 CS3 N"),
+	PINCTRL_PIN(309, "P PAD VDD 25"),
+	PINCTRL_PIN(310, "P PAD GND 25"),
+	PINCTRL_PIN(311, "P PAD VSSIO 39"),
+	PINCTRL_PIN(312, "P PAD VDDIO 39"),
+	PINCTRL_PIN(313, "PO EMIF 1 CS2 N"),
+	PINCTRL_PIN(314, "PO EMIF 1 CS1 N"),
+	PINCTRL_PIN(315, "PO EMIF 1 CS0 N"),
+	PINCTRL_PIN(316, "PO ETM TRACE PKT0"),
+	PINCTRL_PIN(317, "PO ETM TRACE PKT1"),
+	PINCTRL_PIN(318, "PO ETM TRACE PKT2"),
+	PINCTRL_PIN(319, "P PAD VDD 30"),
+	PINCTRL_PIN(320, "P PAD GND 30"),
+	PINCTRL_PIN(321, "P PAD VSSIO 44"),
+	PINCTRL_PIN(322, "P PAD VDDIO 44"),
+	PINCTRL_PIN(323, "PO ETM TRACE PKT3"),
+	PINCTRL_PIN(324, "PO ETM TRACE PKT4"),
+	PINCTRL_PIN(325, "PO ETM TRACE PKT5"),
+	PINCTRL_PIN(326, "PO ETM TRACE PKT6"),
+	PINCTRL_PIN(327, "PO ETM TRACE PKT7"),
+	PINCTRL_PIN(328, "PO ETM PIPE STAT0"),
+	PINCTRL_PIN(329, "P PAD VDD 26"),
+	PINCTRL_PIN(330, "P PAD GND 26"),
+	PINCTRL_PIN(331, "P PAD VSSIO 40"),
+	PINCTRL_PIN(332, "P PAD VDDIO 40"),
+	PINCTRL_PIN(333, "PO ETM PIPE STAT1"),
+	PINCTRL_PIN(334, "PO ETM PIPE STAT2"),
+	PINCTRL_PIN(335, "PO ETM TRACE CLK"),
+	PINCTRL_PIN(336, "PO ETM TRACE SYNC"),
+	PINCTRL_PIN(337, "PIO ACC GPIO 33"),
+	PINCTRL_PIN(338, "PIO ACC GPIO 32"),
+	PINCTRL_PIN(339, "PIO ACC GPIO 30"),
+	PINCTRL_PIN(340, "PIO ACC GPIO 29"),
+	PINCTRL_PIN(341, "P PAD VDDIO 17"),
+	PINCTRL_PIN(342, "P PAD VSSIO 17"),
+	PINCTRL_PIN(343, "P PAD GND 15"),
+	PINCTRL_PIN(344, "P PAD VDD 15"),
+	PINCTRL_PIN(345, "PIO ACC GPIO 28"),
+	PINCTRL_PIN(346, "PIO ACC GPIO 27"),
+	PINCTRL_PIN(347, "PIO ACC GPIO 16"),
+	PINCTRL_PIN(348, "PI TAP TMS"),
+	PINCTRL_PIN(349, "PI TAP TDI"),
+	PINCTRL_PIN(350, "PO TAP TDO"),
+	PINCTRL_PIN(351, "PI TAP RST N"),
+	/* Pads along the left edge of the chip */
+	PINCTRL_PIN(352, "PI EMU MODE 0"),
+	PINCTRL_PIN(353, "PO TAP RET CLK"),
+	PINCTRL_PIN(354, "PI TAP CLK"),
+	PINCTRL_PIN(355, "PO EMIF 0 SD CS N"),
+	PINCTRL_PIN(356, "PO EMIF 0 SD CAS N"),
+	PINCTRL_PIN(357, "PO EMIF 0 SD WE N"),
+	PINCTRL_PIN(358, "P PAD VDDIO 1"),
+	PINCTRL_PIN(359, "P PAD VSSIO 1"),
+	PINCTRL_PIN(360, "P PAD GND 1"),
+	PINCTRL_PIN(361, "P PAD VDD 1"),
+	PINCTRL_PIN(362, "PO EMIF 0 SD CKE"),
+	PINCTRL_PIN(363, "PO EMIF 0 SD DQML"),
+	PINCTRL_PIN(364, "PO EMIF 0 SD DQMU"),
+	PINCTRL_PIN(365, "PO EMIF 0 SD RAS N"),
+	PINCTRL_PIN(366, "PIO EMIF 0 D15"),
+	PINCTRL_PIN(367, "PO EMIF 0 A15"),
+	PINCTRL_PIN(368, "PIO EMIF 0 D14"),
+	PINCTRL_PIN(369, "PO EMIF 0 A14"),
+	PINCTRL_PIN(370, "PIO EMIF 0 D13"),
+	PINCTRL_PIN(371, "PO EMIF 0 A13"),
+	PINCTRL_PIN(372, "P PAD VDDIO 2"),
+	PINCTRL_PIN(373, "P PAD VSSIO 2"),
+	PINCTRL_PIN(374, "P PAD GND 2"),
+	PINCTRL_PIN(375, "P PAD VDD 2"),
+	PINCTRL_PIN(376, "PIO EMIF 0 D12"),
+	PINCTRL_PIN(377, "PO EMIF 0 A12"),
+	PINCTRL_PIN(378, "PIO EMIF 0 D11"),
+	PINCTRL_PIN(379, "PO EMIF 0 A11"),
+	PINCTRL_PIN(380, "PIO EMIF 0 D10"),
+	PINCTRL_PIN(381, "PO EMIF 0 A10"),
+	PINCTRL_PIN(382, "PIO EMIF 0 D09"),
+	PINCTRL_PIN(383, "PO EMIF 0 A09"),
+	PINCTRL_PIN(384, "PIO EMIF 0 D08"),
+	PINCTRL_PIN(385, "PO EMIF 0 A08"),
+	PINCTRL_PIN(386, "PIO EMIF 0 D07"),
+	PINCTRL_PIN(387, "PO EMIF 0 A07"),
+	PINCTRL_PIN(388, "P PAD VDDIO 3"),
+	PINCTRL_PIN(389, "P PAD VSSIO 3"),
+	PINCTRL_PIN(390, "P PAD GND 3"),
+	PINCTRL_PIN(391, "P PAD VDD 3"),
+	PINCTRL_PIN(392, "PO EFUSE RDOUT1"),
+	PINCTRL_PIN(393, "PIO EMIF 0 D06"),
+	PINCTRL_PIN(394, "PO EMIF 0 A06"),
+	PINCTRL_PIN(395, "PIO EMIF 0 D05"),
+	PINCTRL_PIN(396, "PO EMIF 0 A05"),
+	PINCTRL_PIN(397, "PIO EMIF 0 D04"),
+	PINCTRL_PIN(398, "PO EMIF 0 A04"),
+	PINCTRL_PIN(399, "A PADS/A VDDCO1v82v5 GND 80U SF LIN VDDCO AF"),
+	PINCTRL_PIN(400, "PWR VDDCO AF"),
+	PINCTRL_PIN(401, "PWR EFUSE HV1"),
+	PINCTRL_PIN(402, "P PAD VSSIO 4"),
+	PINCTRL_PIN(403, "P PAD VDDIO 4"),
+	PINCTRL_PIN(404, "P PAD GND 4"),
+	PINCTRL_PIN(405, "P PAD VDD 4"),
+	PINCTRL_PIN(406, "PIO EMIF 0 D03"),
+	PINCTRL_PIN(407, "PO EMIF 0 A03"),
+	PINCTRL_PIN(408, "PWR EFUSE HV2"),
+	PINCTRL_PIN(409, "PWR EFUSE HV3"),
+	PINCTRL_PIN(410, "PIO EMIF 0 D02"),
+	PINCTRL_PIN(411, "PO EMIF 0 A02"),
+	PINCTRL_PIN(412, "PIO EMIF 0 D01"),
+	PINCTRL_PIN(413, "P PAD VDDIO 5"),
+	PINCTRL_PIN(414, "P PAD VSSIO 5"),
+	PINCTRL_PIN(415, "P PAD GND 5"),
+	PINCTRL_PIN(416, "P PAD VDD 5"),
+	PINCTRL_PIN(417, "PO EMIF 0 A01"),
+	PINCTRL_PIN(418, "PIO EMIF 0 D00"),
+	PINCTRL_PIN(419, "IF 0 SD CLK"),
+	PINCTRL_PIN(420, "APP SPI CLK"),
+	PINCTRL_PIN(421, "APP SPI DO"),
+	PINCTRL_PIN(422, "APP SPI DI"),
+	PINCTRL_PIN(423, "APP SPI CS0"),
+	PINCTRL_PIN(424, "APP SPI CS1"),
+	PINCTRL_PIN(425, "APP SPI CS2"),
+	PINCTRL_PIN(426, "PIO APP GPIO 10"),
+	PINCTRL_PIN(427, "P PAD VDDIO 41"),
+	PINCTRL_PIN(428, "P PAD VSSIO 41"),
+	PINCTRL_PIN(429, "P PAD GND 6"),
+	PINCTRL_PIN(430, "P PAD VDD 6"),
+	PINCTRL_PIN(431, "PIO ACC SDIO0 CMD"),
+	PINCTRL_PIN(432, "PIO ACC SDIO0 CK"),
+	PINCTRL_PIN(433, "PIO ACC SDIO0 D3"),
+	PINCTRL_PIN(434, "PIO ACC SDIO0 D2"),
+	PINCTRL_PIN(435, "PIO ACC SDIO0 D1"),
+	PINCTRL_PIN(436, "PIO ACC SDIO0 D0"),
+	PINCTRL_PIN(437, "PIO USB PU"),
+	PINCTRL_PIN(438, "PIO USB SP"),
+	PINCTRL_PIN(439, "PIO USB DAT VP"),
+	PINCTRL_PIN(440, "PIO USB SE0 VM"),
+	PINCTRL_PIN(441, "PIO USB OE"),
+	PINCTRL_PIN(442, "PIO USB SUSP"),
+	PINCTRL_PIN(443, "P PAD VSSIO 6"),
+	PINCTRL_PIN(444, "P PAD VDDIO 6"),
+	PINCTRL_PIN(445, "PIO USB PUEN"),
+	PINCTRL_PIN(446, "PIO ACC UART0 RX"),
+	PINCTRL_PIN(447, "PIO ACC UART0 TX"),
+	PINCTRL_PIN(448, "PIO ACC UART0 CTS"),
+	PINCTRL_PIN(449, "PIO ACC UART0 RTS"),
+	PINCTRL_PIN(450, "PIO ACC UART3 RX"),
+	PINCTRL_PIN(451, "PIO ACC UART3 TX"),
+	PINCTRL_PIN(452, "PIO ACC UART3 CTS"),
+	PINCTRL_PIN(453, "PIO ACC UART3 RTS"),
+	PINCTRL_PIN(454, "PIO ACC IRDA TX"),
+	PINCTRL_PIN(455, "P PAD VDDIO 7"),
+	PINCTRL_PIN(456, "P PAD VSSIO 7"),
+	PINCTRL_PIN(457, "P PAD GND 7"),
+	PINCTRL_PIN(458, "P PAD VDD 7"),
+	PINCTRL_PIN(459, "PIO ACC IRDA RX"),
+	PINCTRL_PIN(460, "PIO ACC PCM I2S CLK"),
+	PINCTRL_PIN(461, "PIO ACC PCM I2S WS"),
+	PINCTRL_PIN(462, "PIO ACC PCM I2S DATA A"),
+	PINCTRL_PIN(463, "PIO ACC PCM I2S DATA B"),
+	PINCTRL_PIN(464, "PO SIM CLK"),
+	PINCTRL_PIN(465, "PIO ACC IRDA SD"),
+	PINCTRL_PIN(466, "PIO SIM DATA"),
+};
+
+/**
+ * @dev: a pointer back to containing device
+ * @virtbase: the offset to the controller in virtual memory
+ */
+struct u300_pmx {
+	struct device *dev;
+	struct pinctrl_dev *pctl;
+	u32 phybase;
+	u32 physize;
+	void __iomem *virtbase;
+};
+
+/**
+ * u300_pmx_registers - the array of registers read/written for each pinmux
+ * shunt setting
+ */
+const u32 u300_pmx_registers[] = {
+	U300_SYSCON_PMC1LR,
+	U300_SYSCON_PMC1HR,
+	U300_SYSCON_PMC2R,
+	U300_SYSCON_PMC3R,
+	U300_SYSCON_PMC4R,
+};
+
+/**
+ * struct u300_pin_group - describes a U300 pin group
+ * @name: the name of this specific pin group
+ * @pins: an array of discrete physical pins used in this group, taken
+ *	from the driver-local pin enumeration space
+ * @num_pins: the number of pins in this group array, i.e. the number of
+ *	elements in .pins so we can iterate over that array
+ */
+struct u300_pin_group {
+	const char *name;
+	const unsigned int *pins;
+	const unsigned num_pins;
+};
+
+/**
+ * struct pmx_onmask - mask bits to enable/disable padmux
+ * @mask: mask bits to disable
+ * @val: mask bits to enable
+ *
+ * onmask lazy dog:
+ * onmask = {
+ *   {"PMC1LR" mask, "PMC1LR" value},
+ *   {"PMC1HR" mask, "PMC1HR" value},
+ *   {"PMC2R"  mask, "PMC2R"  value},
+ *   {"PMC3R"  mask, "PMC3R"  value},
+ *   {"PMC4R"  mask, "PMC4R"  value}
+ * }
+ */
+struct u300_pmx_mask {
+	u16 mask;
+	u16 bits;
+};
+
+/* The chip power pins are VDD, GND, VDDIO and VSSIO */
+static const unsigned power_pins[] = { 0, 1, 3, 31, 46, 47, 49, 50, 61, 62, 63,
+	64, 78, 79, 80, 81, 92, 93, 94, 95, 101, 102, 103, 104, 115, 116, 117,
+	118, 130, 131, 132, 133, 145, 146, 147, 148, 159, 160, 172, 173, 174,
+	175, 187, 188, 189, 190, 201, 202, 211, 212, 213, 214, 215, 218, 223,
+	224, 225, 226, 231, 232, 237, 238, 239, 240, 245, 246, 251, 252, 256,
+	257, 258, 259, 264, 265, 270, 271, 276, 277, 278, 279, 284, 285, 290,
+	291, 295, 296, 299, 300, 301, 302, 303, 309, 310, 311, 312, 319, 320,
+	321, 322, 329, 330, 331, 332, 341, 342, 343, 344, 358, 359, 360, 361,
+	372, 373, 374, 375, 388, 389, 390, 391, 402, 403, 404, 405, 413, 414,
+	415, 416, 427, 428, 429, 430, 443, 444, 455, 456, 457, 458 };
+static const unsigned emif0_pins[] = { 355, 356, 357, 362, 363, 364, 365, 366,
+	367, 368, 369, 370, 371, 376, 377, 378, 379, 380, 381, 382, 383, 384,
+	385, 386, 387, 393, 394, 395, 396, 397, 398, 406, 407, 410, 411, 412,
+	417, 418 };
+static const unsigned emif1_pins[] = { 216, 217, 219, 220, 221, 222, 227, 228,
+	229, 230, 233, 234, 235, 236, 241, 242, 243, 244, 247, 248, 249, 250,
+	253, 254, 255, 260, 261, 262, 263, 266, 267, 268, 269, 272, 273, 274,
+	275, 280, 281, 282, 283, 286, 287, 288, 289, 292, 293, 294, 297, 298,
+	304, 305, 306, 307, 308, 313, 314, 315 };
+static const unsigned uart0_pins[] = { 134, 135, 136, 137 };
+static const unsigned mmc0_pins[] = { 166, 167, 168, 169, 170, 171, 176, 177 };
+static const unsigned spi0_pins[] = { 420, 421, 422, 423, 424, 425 };
+
+static const struct u300_pmx_mask emif0_mask[] = {
+	{0, 0},
+	{0, 0},
+	{0, 0},
+	{0, 0},
+	{0, 0},
+};
+
+static const struct u300_pmx_mask emif1_mask[] = {
+	/*
+	 * This connects the SDRAM to CS2 and a NAND flash to
+	 * CS0 on the EMIF.
+	 */
+	{
+		U300_SYSCON_PMC1LR_EMIF_1_CS2_MASK |
+		U300_SYSCON_PMC1LR_EMIF_1_CS1_MASK |
+		U300_SYSCON_PMC1LR_EMIF_1_CS0_MASK |
+		U300_SYSCON_PMC1LR_EMIF_1_MASK,
+		U300_SYSCON_PMC1LR_EMIF_1_CS2_SDRAM |
+		U300_SYSCON_PMC1LR_EMIF_1_CS1_STATIC |
+		U300_SYSCON_PMC1LR_EMIF_1_CS0_NFIF |
+		U300_SYSCON_PMC1LR_EMIF_1_SDRAM0
+	},
+	{0, 0},
+	{0, 0},
+	{0, 0},
+	{0, 0},
+};
+
+static const struct u300_pmx_mask uart0_mask[] = {
+	{0, 0},
+	{
+		U300_SYSCON_PMC1HR_APP_UART0_1_MASK |
+		U300_SYSCON_PMC1HR_APP_UART0_2_MASK,
+		U300_SYSCON_PMC1HR_APP_UART0_1_UART0 |
+		U300_SYSCON_PMC1HR_APP_UART0_2_UART0
+	},
+	{0, 0},
+	{0, 0},
+	{0, 0},
+};
+
+static const struct u300_pmx_mask mmc0_mask[] = {
+	{ U300_SYSCON_PMC1LR_MMCSD_MASK, U300_SYSCON_PMC1LR_MMCSD_MMCSD},
+	{0, 0},
+	{0, 0},
+	{0, 0},
+	{ U300_SYSCON_PMC4R_APP_MISC_12_MASK,
+	  U300_SYSCON_PMC4R_APP_MISC_12_APP_GPIO }
+};
+
+static const struct u300_pmx_mask spi0_mask[] = {
+	{0, 0},
+	{
+		U300_SYSCON_PMC1HR_APP_SPI_2_MASK |
+		U300_SYSCON_PMC1HR_APP_SPI_CS_1_MASK |
+		U300_SYSCON_PMC1HR_APP_SPI_CS_2_MASK,
+		U300_SYSCON_PMC1HR_APP_SPI_2_SPI |
+		U300_SYSCON_PMC1HR_APP_SPI_CS_1_SPI |
+		U300_SYSCON_PMC1HR_APP_SPI_CS_2_SPI
+	},
+	{0, 0},
+	{0, 0},
+	{0, 0}
+};
+
+static const struct u300_pin_group u300_pin_groups[] = {
+	{
+		.name = "powergrp",
+		.pins = power_pins,
+		.num_pins = ARRAY_SIZE(power_pins),
+	},
+	{
+		.name = "emif0grp",
+		.pins = emif0_pins,
+		.num_pins = ARRAY_SIZE(emif0_pins),
+	},
+	{
+		.name = "emif1grp",
+		.pins = emif1_pins,
+		.num_pins = ARRAY_SIZE(emif1_pins),
+	},
+	{
+		.name = "uart0grp",
+		.pins = uart0_pins,
+		.num_pins = ARRAY_SIZE(uart0_pins),
+	},
+	{
+		.name = "mmc0grp",
+		.pins = mmc0_pins,
+		.num_pins = ARRAY_SIZE(mmc0_pins),
+	},
+	{
+		.name = "spi0grp",
+		.pins = spi0_pins,
+		.num_pins = ARRAY_SIZE(spi0_pins),
+	},
+};
+
+static int u300_list_groups(struct pinctrl_dev *pctldev, unsigned selector)
+{
+	if (selector >= ARRAY_SIZE(u300_pin_groups))
+		return -EINVAL;
+	return 0;
+}
+
+static const char *u300_get_group_name(struct pinctrl_dev *pctldev,
+				       unsigned selector)
+{
+	if (selector >= ARRAY_SIZE(u300_pin_groups))
+		return NULL;
+	return u300_pin_groups[selector].name;
+}
+
+static int u300_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
+			       unsigned ** const pins,
+			       unsigned * const num_pins)
+{
+	if (selector >= ARRAY_SIZE(u300_pin_groups))
+		return -EINVAL;
+	*pins = (unsigned *) u300_pin_groups[selector].pins;
+	*num_pins = u300_pin_groups[selector].num_pins;
+	return 0;
+}
+
+static void u300_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
+		   unsigned offset)
+{
+	seq_printf(s, " " DRIVER_NAME);
+}
+
+static struct pinctrl_ops u300_pctrl_ops = {
+	.list_groups = u300_list_groups,
+	.get_group_name = u300_get_group_name,
+	.get_group_pins = u300_get_group_pins,
+	.pin_dbg_show = u300_pin_dbg_show,
+};
+
+/*
+ * Here we define the available functions and their corresponding pin groups
+ */
+
+/**
+ * struct u300_pmx_func - describes U300 pinmux functions
+ * @name: the name of this specific function
+ * @groups: corresponding pin groups
+ * @onmask: bits to set to enable this when doing pin muxing
+ */
+struct u300_pmx_func {
+	const char *name;
+	const char * const *groups;
+	const unsigned num_groups;
+	const struct u300_pmx_mask *mask;
+};
+
+static const char * const powergrps[] = { "powergrp" };
+static const char * const emif0grps[] = { "emif0grp" };
+static const char * const emif1grps[] = { "emif1grp" };
+static const char * const uart0grps[] = { "uart0grp" };
+static const char * const mmc0grps[] = { "mmc0grp" };
+static const char * const spi0grps[] = { "spi0grp" };
+
+static const struct u300_pmx_func u300_pmx_functions[] = {
+	{
+		.name = "power",
+		.groups = powergrps,
+		.num_groups = ARRAY_SIZE(powergrps),
+		/* Mask is N/A */
+	},
+	{
+		.name = "emif0",
+		.groups = emif0grps,
+		.num_groups = ARRAY_SIZE(emif0grps),
+		.mask = emif0_mask,
+	},
+	{
+		.name = "emif1",
+		.groups = emif1grps,
+		.num_groups = ARRAY_SIZE(emif1grps),
+		.mask = emif1_mask,
+	},
+	{
+		.name = "uart0",
+		.groups = uart0grps,
+		.num_groups = ARRAY_SIZE(uart0grps),
+		.mask = uart0_mask,
+	},
+	{
+		.name = "mmc0",
+		.groups = mmc0grps,
+		.num_groups = ARRAY_SIZE(mmc0grps),
+		.mask = mmc0_mask,
+	},
+	{
+		.name = "spi0",
+		.groups = spi0grps,
+		.num_groups = ARRAY_SIZE(spi0grps),
+		.mask = spi0_mask,
+	},
+};
+
+static void u300_pmx_endisable(struct u300_pmx *upmx, unsigned selector,
+			       bool enable)
+{
+	u16 regval, val, mask;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(u300_pmx_registers); i++) {
+		if (enable)
+			val = u300_pmx_functions[selector].mask->bits;
+		else
+			val = 0;
+
+		mask = u300_pmx_functions[selector].mask->mask;
+		if (mask != 0) {
+			regval = readw(upmx->virtbase + u300_pmx_registers[i]);
+			regval &= ~mask;
+			regval |= val;
+			writew(regval, upmx->virtbase + u300_pmx_registers[i]);
+		}
+	}
+}
+
+static int u300_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector,
+			   unsigned group)
+{
+	struct u300_pmx *upmx;
+
+	/* There is nothing to do with the power pins */
+	if (selector == 0)
+		return 0;
+
+	upmx = pctldev_get_drvdata(pctldev);
+	u300_pmx_endisable(upmx, selector, true);
+
+	return 0;
+}
+
+static void u300_pmx_disable(struct pinctrl_dev *pctldev, unsigned selector,
+			     unsigned group)
+{
+	struct u300_pmx *upmx;
+
+	/* There is nothing to do with the power pins */
+	if (selector == 0)
+		return;
+
+	upmx = pctldev_get_drvdata(pctldev);
+	u300_pmx_endisable(upmx, selector, false);
+}
+
+static int u300_pmx_list_funcs(struct pinctrl_dev *pctldev, unsigned selector)
+{
+	if (selector >= ARRAY_SIZE(u300_pmx_functions))
+		return -EINVAL;
+	return 0;
+}
+
+static const char *u300_pmx_get_func_name(struct pinctrl_dev *pctldev,
+					  unsigned selector)
+{
+	return u300_pmx_functions[selector].name;
+}
+
+static int u300_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
+			       const char * const **groups,
+			       unsigned * const num_groups)
+{
+	*groups = u300_pmx_functions[selector].groups;
+	*num_groups = u300_pmx_functions[selector].num_groups;
+	return 0;
+}
+
+static struct pinmux_ops u300_pmx_ops = {
+	.list_functions = u300_pmx_list_funcs,
+	.get_function_name = u300_pmx_get_func_name,
+	.get_function_groups = u300_pmx_get_groups,
+	.enable = u300_pmx_enable,
+	.disable = u300_pmx_disable,
+};
+
+/*
+ * FIXME: this will be set to sane values as this driver engulfs
+ * drivers/gpio/gpio-u300.c and we really know this stuff.
+ */
+static struct pinctrl_gpio_range u300_gpio_range = {
+	.name = "COH901*",
+	.id = 0,
+	.base = 0,
+	.npins = 64,
+};
+
+static struct pinctrl_desc u300_pmx_desc = {
+	.name = DRIVER_NAME,
+	.pins = u300_pads,
+	.npins = ARRAY_SIZE(u300_pads),
+	.maxpin = U300_NUM_PADS-1,
+	.pctlops = &u300_pctrl_ops,
+	.pmxops = &u300_pmx_ops,
+	.owner = THIS_MODULE,
+};
+
+static void __init u300_pmx_dumpregs(struct u300_pmx *upmx)
+{
+	u16 regval;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(u300_pmx_registers); i++) {
+		regval = readw(upmx->virtbase + u300_pmx_registers[i]);
+		dev_info(upmx->dev, "PMX%u: 0x%04x\n", i, regval);
+	}
+}
+
+static int __init u300_pmx_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct u300_pmx *upmx;
+	struct resource *res;
+
+	/* Create state holders etc for this driver */
+	upmx = devm_kzalloc(&pdev->dev, sizeof(struct u300_pmx), GFP_KERNEL);
+	if (!upmx)
+		return -ENOMEM;
+
+	upmx->dev = &pdev->dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = -ENOENT;
+		goto out_no_resource;
+	}
+	upmx->phybase = res->start;
+	upmx->physize = resource_size(res);
+
+	if (request_mem_region(upmx->phybase, upmx->physize,
+			       DRIVER_NAME) == NULL) {
+		ret = -EBUSY;
+		goto out_no_memregion;
+	}
+
+	upmx->virtbase = ioremap(upmx->phybase, upmx->physize);
+	if (!upmx->virtbase) {
+		ret = -ENOMEM;
+		goto out_no_remap;
+	}
+
+	upmx->pctl = pinctrl_register(&u300_pmx_desc, &pdev->dev, upmx);
+	if (IS_ERR(upmx->pctl)) {
+		dev_err(&pdev->dev, "could not register U300 pinmux driver\n");
+		ret = PTR_ERR(upmx->pctl);
+		goto out_no_pmx;
+	}
+
+	/* We will handle a range of GPIO pins */
+	pinctrl_add_gpio_range(upmx->pctl, &u300_gpio_range);
+
+	platform_set_drvdata(pdev, upmx);
+
+	u300_pmx_dumpregs(upmx);
+
+	dev_info(&pdev->dev, "initialized U300 pinmux driver\n");
+
+	return 0;
+
+out_no_pmx:
+	iounmap(upmx->virtbase);
+out_no_remap:
+	platform_set_drvdata(pdev, NULL);
+out_no_memregion:
+	release_mem_region(upmx->phybase, upmx->physize);
+out_no_resource:
+	devm_kfree(&pdev->dev, upmx);
+	return ret;
+}
+
+static int __exit u300_pmx_remove(struct platform_device *pdev)
+{
+	struct u300_pmx *upmx = platform_get_drvdata(pdev);
+
+	pinctrl_remove_gpio_range(upmx->pctl, &u300_gpio_range);
+	pinctrl_unregister(upmx->pctl);
+	iounmap(upmx->virtbase);
+	release_mem_region(upmx->phybase, upmx->physize);
+	platform_set_drvdata(pdev, NULL);
+	devm_kfree(&pdev->dev, upmx);
+
+	return 0;
+}
+
+static struct platform_driver u300_pmx_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+	},
+	.remove = __exit_p(u300_pmx_remove),
+};
+
+static int __init u300_pmx_init(void)
+{
+	return platform_driver_probe(&u300_pmx_driver, u300_pmx_probe);
+}
+arch_initcall(u300_pmx_init);
+
+static void __exit u300_pmx_exit(void)
+{
+	platform_driver_unregister(&u300_pmx_driver);
+}
+module_exit(u300_pmx_exit);
+
+MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
+MODULE_DESCRIPTION("U300 pin control driver");
+MODULE_LICENSE("GPL v2");
-- 
1.7.3.2

^ permalink raw reply related

* [PATCH v2] OMAP2PLUS: DSS: Ensure DSS works correctly if display is enabled in bootloader
From: Tomi Valkeinen @ 2011-10-03  8:21 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <alpine.DEB.2.00.1110022237171.4611@utopia.booyaka.com>

Hi Paul,

On Sun, 2011-10-02 at 22:45 -0600, Paul Walmsley wrote:
> Hi
> 
> some comments:
> 
> On Mon, 12 Sep 2011, Archit Taneja wrote:
> 
> > Resetting DISPC when a DISPC output is enabled causes the DSS to go into an
> > inconsistent state. Thus if the bootloader has enabled a display, the hwmod code
> > cannot reset the DISPC module just like that, but the outputs need to be
> > disabled first.
> > 
> > Add function dispc_disable_outputs() which disables all active overlay manager
> > and ensure all frame transfers are completed.
> > 
> > Modify omap_dss_reset() to call this function and clear DSS_CONTROL,
> > DSS_SDI_CONTROL and DSS_PLL_CONTROL so that DSS is in a clean state when the
> > DSS2 driver starts.
> > 
> > This resolves the hang issue(caused by a L3 error during boot) seen on the
> > beagle board C3, which has a factory bootloader that enables display. The issue
> > is resolved with this patch.

<snip>

> +struct omap_dss_dispc_dev_attr {
> +	u8	manager_count;
> +	bool	has_framedonetv_irq;
> +};
> +
> +#endif
> diff --git a/arch/arm/mach-omap2/omap_hwmod_2420_data.c b/arch/arm/mach-omap2/omap_hwmod_2420_data.c
> index 09d9395..8e32cb3 100644
> --- a/arch/arm/mach-omap2/omap_hwmod_2420_data.c
> +++ b/arch/arm/mach-omap2/omap_hwmod_2420_data.c
> @@ -945,6 +945,7 @@ static struct omap_hwmod omap2420_dss_dispc_hwmod = {
>  	.slaves_cnt	= ARRAY_SIZE(omap2420_dss_dispc_slaves),
>  	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
>  	.flags		= HWMOD_NO_IDLEST,
> +	.dev_attr	= &omap2_3_dss_dispc_dev_attr
>  };

I didn't know you can add arbitrary data like that to hwmods. What kind
of data is it meant for? Can the data be used by the driver, or is it
meant just for arch stuff?

I'm wondering this as we have a complex mechanism in the dss driver to
find out about the differences of DSS hardware
(drivers/video/omap2/dss/dss_features.[ch]). The dss_features system is
currently part of the driver, but should be moved under arch/arm/*omap*
at some point, and this hwmod dev_attr sounds like it could possibly be
a right place to handle these.

I looked at how the dev_attrs are used, and all of them seemed to be
very small, a few fields at max. The DSS features set is, on the other
hand, quite big amount of data, and meant for the driver.

 Tomi

^ permalink raw reply

* [GIT PULL] DEBUG_LL platform updates for 3.2
From: Will Deacon @ 2011-10-03  8:35 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20110928103815.GA8344@e102144-lin.cambridge.arm.com>

Arnd,

On Wed, Sep 28, 2011 at 11:38:15AM +0100, Will Deacon wrote:
> Please pull these DEBUG_LL platform updates for 3.2. You can find the core
> updates (actually all resident in arch/arm/Kconfig.debug) in Russell's
> for-next branch.

[...]

> The following changes since commit 589593ec8b1790c0d9ea227a3811f819eff4f977:
>   Stephen Boyd (1):
>         ARM: 7097/1: debug: Move DEBUG_ICEDCC into the DEBUG_LL choice
> 
> are available in the git repository at:
> 
>   git://linux-arm.org/linux-2.6-wd.git for-arnd

My git server has been up and down like a yo-yo recently, so if you tried to
pull this and it failed, hopefully it's all been fixed now.

Will

^ permalink raw reply

* [PATCH 2/3] define ARM-specific dma_coherent_write_sync
From: Catalin Marinas @ 2011-10-03  8:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <026571E7-67F6-4B0F-998C-2A845AA22E59@jonmasters.org>

On Mon, Oct 03, 2011 at 02:40:19AM +0100, Jon Masters wrote:
> On Sep 6, 2011, at 11:02 AM, Mark Salter wrote:
> > In any case, the current thinking is that the original problem with
> > the USB performance seen on cortex A9 multicore is probably something
> > more than just write buffer delays. Once the original problem is better
> > understood, we can take another look at this patch if it is still
> > needed.
> 
> Thanks again for looking into this Mark. My understanding is that this
> is still being investigated. I'll followup with ARM to see how that's
> going since I've heard nothing recently :) Meanwhile, we're continuing
> to carry a hack based on these patches in Fedora ARM kernels.

Not talking about hardware specifics here, the architecture (though
ARMv7 onwards) mandates that the write buffer is eventually drained. But
doesn't state any upper limit, so it could even be half a second.

In this case, some form of buffer draining for devices that poll the
memory may be useful. If we don't want to add a new API, something like
below would work as well:

	write to DMA buffer;
	mb();
	read from DMA buffer;

So an mb() between the last write and a subsequent read would force the
visibility of the write. We have similar scenarios for Device accesses.

If we go for a DMA API extension, the dma_coherent_write_sync() should
probably take an address as well, just in case implementations would
force the draining via some read back from the same area.

-- 
Catalin

^ permalink raw reply

* [PATCH 3/3] tty/serial: atmel_serial: __devinit_p for probe function
From: Russell King - ARM Linux @ 2011-10-03  8:50 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <cd489c1d28c26624d6b68399d222aec371045e53.1317634987.git.nicolas.ferre@atmel.com>

On Mon, Oct 03, 2011 at 11:46:16AM +0200, Nicolas Ferre wrote:
> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
> ---
>  drivers/tty/serial/atmel_serial.c |    2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
> index a652f8f..453cdb5 100644
> --- a/drivers/tty/serial/atmel_serial.c
> +++ b/drivers/tty/serial/atmel_serial.c
> @@ -1789,7 +1789,7 @@ static int __devexit atmel_serial_remove(struct platform_device *pdev)
>  }
>  
>  static struct platform_driver atmel_serial_driver = {
> -	.probe		= atmel_serial_probe,
> +	.probe		= __devexit_p(atmel_serial_probe),

That doesn't match the patch description (and is probably wrong.)

^ permalink raw reply

* [PATCH V2] AT91: dt: at91sam9g45 family and board device tree files
From: Russell King - ARM Linux @ 2011-10-03  8:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1317636056-9537-1-git-send-email-nicolas.ferre@atmel.com>

On Mon, Oct 03, 2011 at 12:00:56PM +0200, Nicolas Ferre wrote:
> diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c
> new file mode 100644
> index 0000000..7bcb9a9
> --- /dev/null
> +++ b/arch/arm/mach-at91/board-dt.c
> @@ -0,0 +1,122 @@
> +/*
> + *  Setup code for AT91SAM Evaluation Kits with Device Tree support
> + *
> + *  Covers: * AT91SAM9G45-EKES  board
> + *          * AT91SAM9M10-EKES  board
> + *          * AT91SAM9M10G45-EK board
> + *
> + *  Copyright (C) 2011 Atmel,
> + *                2011 Nicolas Ferre <nicolas.ferre@atmel.com>
> + *
> + * Licensed under GPLv2 or later.
> + */
> +
> +#include <linux/types.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/irqdomain.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_platform.h>
> +
> +#include <mach/hardware.h>
> +#include <mach/board.h>
> +#include <mach/gpio.h>

Is linux/gpio.h broken for you?

^ permalink raw reply

* [PATCH] [WATCHDOG] move coh901327 state holders
From: Linus Walleij @ 2011-10-03  8:52 UTC (permalink / raw)
  To: linux-arm-kernel

From: Linus Walleij <linus.walleij@linaro.org>

The state holders used in the PM path of the drivers report as
unused variables when compiling without CONFIG_PM so let's
move them inside CONFIG_PM.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
 drivers/watchdog/coh901327_wdt.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/watchdog/coh901327_wdt.c b/drivers/watchdog/coh901327_wdt.c
index 9291506..20b2fb9 100644
--- a/drivers/watchdog/coh901327_wdt.c
+++ b/drivers/watchdog/coh901327_wdt.c
@@ -76,8 +76,6 @@ static int irq;
 static void __iomem *virtbase;
 static unsigned long coh901327_users;
 static unsigned long boot_status;
-static u16 wdogenablestore;
-static u16 irqmaskstore;
 static struct device *parent;
 
 /*
@@ -461,6 +459,10 @@ out:
 }
 
 #ifdef CONFIG_PM
+
+static u16 wdogenablestore;
+static u16 irqmaskstore;
+
 static int coh901327_suspend(struct platform_device *pdev, pm_message_t state)
 {
 	irqmaskstore = readw(virtbase + U300_WDOG_IMR) & 0x0001U;
-- 
1.7.3.2

^ permalink raw reply related

* [PATCH 3/3] tty/serial: atmel_serial: __devinit_p for probe function
From: Nicolas Ferre @ 2011-10-03  8:56 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20111003085029.GA11710@n2100.arm.linux.org.uk>

On 10/03/2011 10:50 AM, Russell King - ARM Linux :
> On Mon, Oct 03, 2011 at 11:46:16AM +0200, Nicolas Ferre wrote:
>> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
>> ---
>>  drivers/tty/serial/atmel_serial.c |    2 +-
>>  1 files changed, 1 insertions(+), 1 deletions(-)
>>
>> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
>> index a652f8f..453cdb5 100644
>> --- a/drivers/tty/serial/atmel_serial.c
>> +++ b/drivers/tty/serial/atmel_serial.c
>> @@ -1789,7 +1789,7 @@ static int __devexit atmel_serial_remove(struct platform_device *pdev)
>>  }
>>  
>>  static struct platform_driver atmel_serial_driver = {
>> -	.probe		= atmel_serial_probe,
>> +	.probe		= __devexit_p(atmel_serial_probe),
> 
> That doesn't match the patch description (and is probably wrong.)

Yes, indeed.
Sorry for the noise!
-- 
Nicolas Ferre

^ permalink raw reply

* [PATCH 26/30] ARM: omap: add board autoselection
From: Arnd Bergmann @ 2011-10-03  9:11 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <4E8947F7.2070108@ti.com>

On Monday 03 October 2011 10:58:23 Santosh Shilimkar wrote:
> > +config MACH_OMAP_AUTO_BOARD
> > +     def_bool y
> > +     depends on !MACH_OMAP2_TUSB6010
> > +     depends on !MACH_OMAP_H4
> > +     depends on !MACH_OMAP_APOLLON
> > +     depends on !MACH_OMAP_APOLLON
> > +     depends on !MACH_OMAP_2430SDP
> > +     depends on !MACH_OMAP3_BEAGLE
> > +     depends on !MACH_DEVKIT8000
> > +     depends on !MACH_OMAP_LDP
> > +     depends on !MACH_OMAP3530_LV_SOM
> > +     depends on !MACH_OMAP3_TORPEDO
> > +     depends on !MACH_OVERO
> > +     depends on !MACH_OMAP3EVM
> > +     depends on !MACH_OMAP3517EVM
> > +     depends on !MACH_CRANEBOARD
> > +     depends on !MACH_OMAP3_PANDORA
> > +     depends on !MACH_OMAP3_TOUCHBOOK
> > +     depends on !MACH_NOKIA_N8X0
> > +     depends on !MACH_NOKIA_RM680
> > +     depends on !MACH_NOKIA_RX51
> > +     depends on !MACH_OMAP_ZOOM2
> > +     depends on !MACH_OMAP_ZOOM3
> > +     depends on !MACH_CM_T35
> > +     depends on !MACH_CM_T3517
> > +     depends on !MACH_IGEP0020
> > +     depends on !MACH_IGEP0030
> > +     depends on !MACH_SBC3530
> > +     depends on !MACH_OMAP_3630SDP
> > +     depends on !MACH_TI8168EVM
> > +     depends on !MACH_OMAP4_PANDA
> Do we need all above 'depends on *' ?
> Even if they get selected for one of the below
> ARCH along with default machine, build should be happy.
> Right ?

I'm not too happy with having to maintain a list for each subarchitecture,
when each one has the same problem. In general, I would really like to have
the flexibility to disable all but any one board, which requires either
maintaining a list like the above, or expressing the same like

config MACH_OMAP_AUTO_BOARD
	 def_bool y
       depends on !MACH_OMAP_BOARD_SELECTED
       select MACH_OMAP_GENERIC if ARCH_OMAP2
       select MACH_OMAP_3430SDP if ARCH_OMAP3 && !ARCH_OMAP2
       select MACH_OMAP_4430SDP if ARCH_OMAP4 && !ARCH_OMAP3 && !ARCH_OMAP2

and adding a 'select MACH_OMAP_BOARD_SELECTED' for each one. Slightly more
to write but perhaps a little less error-prone.

In the long run, I'd hope we can just get rid of these for subarchitectures
that support device tree probing and make the device tree based machine
description unconditional.

	Arnd

^ permalink raw reply

* [PATCH 28/30] ARM: omap: select CPU_FREQ_TABLE where needed
From: Arnd Bergmann @ 2011-10-03  9:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <4E894A95.5030107@ti.com>

On Monday 03 October 2011 11:09:33 Santosh Shilimkar wrote:
> > diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
> > index bb8f4a6..f7ef9f4 100644
> > --- a/arch/arm/plat-omap/Kconfig
> > +++ b/arch/arm/plat-omap/Kconfig
> > @@ -217,6 +217,11 @@ config OMAP_PM_NOOP
> >  
> >  endchoice
> >  
> > +config OMAP_CPU_FREQ
> > +     def_bool "y"
> > +     depends on CPU_FREQ
> > +     select CPU_FREQ_TABLE
> > +
> >  endmenu
> With CPUFREQ series from Kevin [1], I don't think we need this any-more.

I guess if it's needed, it should at least be moved to the new cpufreq
location.

> More so, I didn't find OMAP_CPU_FREQ is being used anywhere on mainline.

Yes, OMAP_CPU_FREQ is a symbol that is intentionally unused, with the
only purpose of selecting CPU_FREQ_TABLE if any omap platform together
with CPU_FREQ is enabled.

Let's drop this patch for now, if it is still needed as I think, I can
do a patch during the 3.2 cycle for the right location.

	Arnd

^ permalink raw reply

* [PATCH 20/30] media/omap_vout: disable driver for now
From: Arnd Bergmann @ 2011-10-03  9:16 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <4E8951B7.7010106@ti.com>

On Monday 03 October 2011 11:39:59 Archit Taneja wrote:
> 
> A fix for this is already in the master branch of Mauro's tree:
> 
> git://linuxtv.org/media_tree.git
> 
> with the commit id:
> 
> 5ebbf72dc51bd3b481aa91fea37a7157da5fc548
> 
> I am guessing this would during the 3.2 merge window.

Ok, thanks for the info! We can drop this then.

	Arnd

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox