Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* OMAP baseline test results for v3.7-rc1
From: Santosh Shilimkar @ 2012-10-18  8:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1350549436.2143.47.camel@sokoban>

Tero, paul,

On Thursday 18 October 2012 02:07 PM, Tero Kristo wrote:
> On Thu, 2012-10-18 at 06:48 +0000, Paul Walmsley wrote:
>> On Thu, 18 Oct 2012, Paul Walmsley wrote:
>>
>>> Here are some basic OMAP test results for Linux v3.7-rc1.
>>> Logs and other details at http://www.pwsan.com/omap/testlogs/test_v3.7-rc1/
>>
>> A few additional observations missing from the original message.
>>
>>> Failing tests: needing investigation
>>> ------------------------------------
>>>
>>> Boot tests:
>>>
>>> * 2420n800: boot hangs during UART initialization
>>>    - http://lkml.org/lkml/2012/9/11/454
>>>    - Various attempts at fixes posted; etiology known; issue still unresolved
>>>
>>> * CM-T3517: L3 in-band error with IPSS during boot
>>>    - Cause unknown but see http://marc.info/?l=linux-omap&m=134833869730129&w=2
>>>    - Longstanding issue; does not occur on the 3517EVM
>>>
>>> * 3517EVM & CM-T3517: boot hangs with NFS root
>>>    - Likely some Kconfig, board file, and PM issues with EMAC
>>>
>>> * CM-T3517: boot hangs with MMC boot
>>>    - Due to missing MMC setup in board file
>>
>> * 4430es2panda: clockevents problems early in boot
>>    - boots with dummy_timer
>>    - no one-shot mode so no-HZ is likely to fail
>
> I have a fix for this problem, however I am seeing this on omap4460
> panda. The root cause seems to be that local timer init for OMAP is
> using wrong interrupt number. It adds a wrong offset to the interrupt
> (OMAP_INTC_START) which should be omitted. Will send a patch soon along
> with a new version of core ret set.
>
This one is already fixed by [1] and Tony has sent pull request[1] to
arm-soc maintainers for 3.7-rc1 which includes the fix.

regards
santosh

[1] https://patchwork.kernel.org/patch/1587621/
[2] http://www.mail-archive.com/linux-omap at vger.kernel.org/msg78045.html

^ permalink raw reply

* [PATCH 4/9] ARM: export default read_current_timer
From: Alexander Holler @ 2012-10-18  8:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20121009160647.GG4625@n2100.arm.linux.org.uk>

Am 09.10.2012 18:06, schrieb Russell King - ARM Linux:
> On Tue, Oct 09, 2012 at 04:40:54PM +0100, Jonathan Austin wrote:
>> Hi Arnd,
>>
>> On 09/10/12 16:22, Arnd Bergmann wrote:
>>> diff --git a/arch/arm/lib/delay.c b/arch/arm/lib/delay.c
>>> index 9d0a300..0dc5385 100644
>>> --- a/arch/arm/lib/delay.c
>>> +++ b/arch/arm/lib/delay.c
>>> @@ -45,6 +45,7 @@ int read_current_timer(unsigned long *timer_val)
>>>   	*timer_val = delay_timer->read_current_timer();
>>>   	return 0;
>>>   }
>>> +EXPORT_SYMBOL_GPL(read_current_timer);
>>
>>
>> Perhaps this fits better in armksyms.c? That way it lives with
>> arm_delay_ops and friends.
>
> It's always much better to put things next to where they're defined
> rather than spreading them around.
>
> armksyms.c is a reminant of the 1.x days of doing things... but still
> remains to allow what are mostly assembly symbols to be exported.

I needed that to build udlfb as a module.

For the 3.6 stable kernels this has to be done in
arch/arm/kernel/arch_timer.c (along with an #include <linux/export.h>)

So I'm not sure if an Cc: <stable@vger.kernel.org> can be used here, but 
a patch should be submitted for inclusion into the 3.6 stable series too.

Regards,

Alexander

^ permalink raw reply

* OMAP baseline test results for v3.7-rc1
From: Tero Kristo @ 2012-10-18  8:37 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <alpine.DEB.2.00.1210180644170.15666@utopia.booyaka.com>

On Thu, 2012-10-18 at 06:48 +0000, Paul Walmsley wrote:
> On Thu, 18 Oct 2012, Paul Walmsley wrote:
> 
> > Here are some basic OMAP test results for Linux v3.7-rc1.
> > Logs and other details at http://www.pwsan.com/omap/testlogs/test_v3.7-rc1/
> 
> A few additional observations missing from the original message.
> 
> > Failing tests: needing investigation
> > ------------------------------------
> > 
> > Boot tests:
> > 
> > * 2420n800: boot hangs during UART initialization
> >   - http://lkml.org/lkml/2012/9/11/454
> >   - Various attempts at fixes posted; etiology known; issue still unresolved
> > 
> > * CM-T3517: L3 in-band error with IPSS during boot
> >   - Cause unknown but see http://marc.info/?l=linux-omap&m=134833869730129&w=2
> >   - Longstanding issue; does not occur on the 3517EVM
> > 
> > * 3517EVM & CM-T3517: boot hangs with NFS root
> >   - Likely some Kconfig, board file, and PM issues with EMAC
> > 
> > * CM-T3517: boot hangs with MMC boot
> >   - Due to missing MMC setup in board file
> 
> * 4430es2panda: clockevents problems early in boot
>   - boots with dummy_timer
>   - no one-shot mode so no-HZ is likely to fail

I have a fix for this problem, however I am seeing this on omap4460
panda. The root cause seems to be that local timer init for OMAP is
using wrong interrupt number. It adds a wrong offset to the interrupt
(OMAP_INTC_START) which should be omitted. Will send a patch soon along
with a new version of core ret set.

-Tero

> 
> * 4460pandaes: boot fails early
>   - Appears to be timer-related
> 
> > PM tests:
> > 
> > * 3530es3beagle, 37xxevm, 3730beaglexm: I2C fails during resume from suspend
> >   - Causes MMC to become unusable since regulators are not reenabled
> >   - Can be worked around by reverting the I2C driver conversion to
> >     threaded IRQs:
> >     - http://marc.info/?l=linux-i2c&m=135026587102887&w=2
> >   - Appears to be due to an accounting problem; under discussion:
> >     - http://marc.info/?l=linux-arm-kernel&m=135042360725821&w=2
> > 
> > * 3530es3beagle: hangs during off-mode dynamic idle test
> >   - Unknown cause; not investigated
> > 
> > * 37xx EVM: CORE not entering dynamic off-idle
> >   - Cause unknown; dynamic retention-idle seems to work; system suspend to 
> >     off works
> > 
> > * 3730 Beagle XM: does not serial wake from off-idle suspend when console
> >   UART doesn't clock gate ("debug ignore_loglevel")
> >   - Not shown in the current test logs; cause unknown
> 
> * 4430es2panda: dummy_timer warning messages during resume
>   - Unknown cause; not investigated
> 
> 
> - Paul
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH 2/5] ARM: OMAP3+: hwmod: Add AM33XX HWMOD data for davinci_mdio
From: Koen Kooi @ 2012-10-18  8:30 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20121018030654.GE2867@netboy.at.omicron.at>


Op 18 okt. 2012, om 05:06 heeft Richard Cochran <richardcochran@gmail.com> het volgende geschreven:

> On Wed, Oct 17, 2012 at 04:50:46PM -0700, Tony Lindgren wrote:
>> * Paul Walmsley <paul@pwsan.com> [121017 16:39]:
>>> Hi Richard
>>> 
>>> On Wed, 17 Oct 2012, Richard Cochran wrote:
>>> 
>>>> Would you please take this bugfix for 3.7-rc2? The suggestion to mail
>>>> you came from Toni Lindgren. The context where it came from is here:
>>>> 
>>>> http://lists.arm.linux.org.uk/lurker/message/20121015.191630.bdae3c50.en.html
>>> 
>>> This patch appears to add a new feature, correct?  I don't think the CPSW 
>>> could have worked in the past without this data present.  So it looks to 
>>> me like this is 3.8 material, unless Tony would like it to go in sooner?
>> 
>> Yeah unless it fixes something, we should just queue it for v3.8 merge
>> window.
> 
> So there has been this cpsw driver since v3.4-rc1~177^2~5
> 
>   df82859 netdev: driver: ethernet: Add TI CPSW driver
> 
> and four people signed off on it, so it must have been working at one
> point. Since the device tree make-over, the driver is a derelict, and
> thus the present patch is fixing a regression.

Have a look at the tscadc driver for am335x that has had a few rounds of review. That one lacks DT bindings, so it can't be tested on this DT only platform. That a driver has been accepted in mainline does not mean it works, for am335x it just means that it compiles.

The patches I needed to get cpsw to work on beaglebone: https://github.com/beagleboard/kernel/tree/3.7/patches/cpsw

regards,

Koen

^ permalink raw reply

* [PATCH] dma: add new DMA control commands
From: Huang Shijie @ 2012-10-18  8:29 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201210181016.06782.marex@denx.de>

? 2012?10?18? 16:16, Marek Vasut ??:
> So we can't stream data from the chip? About time to adjust the MTD framework to
> allow that. Maybe implement a command queue?
>

to Artem & David:
    is this possible to stream the data out with a command queue?

thanks
Huang Shijie

^ permalink raw reply

* [PATCH] dma: add new DMA control commands
From: Marek Vasut @ 2012-10-18  8:16 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <507FB495.7050104@freescale.com>

Dear Huang Shijie,

> ? 2012?10?18? 15:14, Marek Vasut ??:
> > Dear Huang Shijie,
> > 
> > Why such massive CC ?
> > 
> >> ? 2012?10?18? 14:18, Vinod Koul ??:
> >>> Why cant you do start (prepare clock etc) when you submit the
> >>> descriptor to dmaengine. Can be done in tx_submit callback.
> >>> Similarly remove the clock when dma transaction gets completed.
> >> 
> >> I ever thought this method too.
> >> 
> >> But it will become low efficient in the following case:
> >>     Assuming the gpmi-nand driver has to read out 1024 pages in one
> >> 
> >> _SINGLE_ read operation.
> >> The gpmi-nand will submit the descriptor to dmaengine per page.
> > 
> > It will? Then GPMI NAND is flat our broken ... again.
> 
> yes.
> 
> Please read the NAND chip spec about the comand READ PAGE(00h-30h) and
> the code
> nand_do_read_ops(). The nand chip limits us only read one page out one
> time. So the driver will submit the descriptor to dmaengine per page.

So we can't stream data from the chip? About time to adjust the MTD framework to 
allow that. Maybe implement a command queue?

> >> So with
> >> your method,
> >> the system will repeat the enable/disable dma clock 1024 time.
> > 
> > Yes, it is the driver that's wrong.
> 
> not the driver.
> 
> >> At every
> >> enable/disable dma clock,
> >> the system has to enable the clock chain and it's parents ...
> >> 
> >> But with this patch, we only need to enable/disable dma clock one time,
> >> just at we select the nand chip.
> > 
> > You are fixing a driver problem at a framework level, wrong.
> > 
> > So, check how the MXS SPI driver handles descriptor chaining. Indeed, the
> > Sigmatel screwed the DMA stuff good. But if you analyze the SPI driver,
> > you'll notice a few important points that might come handy when you fix
> > the GPMI NAND driver properly.
> > 
> > The direction to take here is:
> > 1) Implement DMA chaining into the GPMI NAND driver
> 
> How can i implement the DMA chain if the nand chip READ-PAGE command
> gives us the one page limit?

This smells like a time to extend the MTD api ?

> thanks
> Huang Shijie
> 
> > 2) You might need to do one PIO transfer to reconfigure the IP registers
> > between each segment of the DMA chain (just as MXS SPI does it)
> > 3) You might run out of DMA descriptors when doing too long chains -- so
> > you might need to fix that part of the mxs DMA driver.

Best regards,
Marek Vasut

^ permalink raw reply

* [GIT PULL] Renesas ARM-based SoC defconfig for v3.8
From: Simon Horman @ 2012-10-18  8:13 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <4502243.v9vY3prCgE@wuerfel>

On Thu, Oct 18, 2012 at 07:29:30AM +0000, Arnd Bergmann wrote:
> On Thursday 18 October 2012 09:58:11 Simon Horman wrote:
> > On Wed, Oct 17, 2012 at 01:42:29PM +0000, Arnd Bergmann wrote:
> > > On Wednesday 17 October 2012, Simon Horman wrote:
> > > > Hi Olof, Hi Arnd,
> > > > 
> > > > please consider the following defconfig enhancements for 3.8.
> > > 
> > > These look good to me, but I wonder what happened to the plan to reduce
> > > the number of defconfig files we discussed before. Since you can build
> > > a combined kernel that runs on all (or most) of the supported boards,
> > > can you add a combined shmobile_defconfig that is able to work on
> > > a wide variety of hardware and drop some of the less common defconfig
> > > files?
> > > 
> > > Most of the modern platforms nowadays have just one defconfig that
> > > covers everything.
> > 
> > Hi Arnd,
> > 
> > I wonder if such consolidation only makes sense for boards that
> > make use of DT. If so, I can see that we may be able to come
> > up with a single configuration for the Armadillo800eva, KZM9G
> > and KZM9D boards. But not for older boards such as the Mackerel which
> > have not been converted to use DT.
> 
> Usually you should just be able to enable any boards together,
> independent of whether they are using DT or not. It's possible
> that shmobile does something different from the other platforms
> that I'm not aware of, of course. If you look at e.g.
> omap2plus_defconfig or imx_v6_v7_defconfig, they both enable
> all the available boards.

Thanks, I'll see what I can do within the scope of the boards
that I have access to.

> > I am also wondering if more of the drivers that SH Mobile uses need to
> > become DT aware before a consolidated configuration can work.  In
> > particular, I am thinking about the SCI serial driver and the location of
> > the serial port that can be used for serial console and early printk - this
> > features in the kernel command line of the per-board defconfigs and is
> > relied on by developers.
> 
> Device drivers that don't use DT should get their configuration from
> platform_data. The command line can be used to override those, but it's
> also normally passed by the boot loader, which also has to configure
> e.g. how much memory is present or which uart to use.

Understood.

^ permalink raw reply

* [PATCH] ARM: dts: AM33XX: Add tsl2550 ambient light sensor DT data
From: Benoit Cousson @ 2012-10-18  8:08 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <331ABD5ECB02734CA317220B2BBEABC13EA53C2B@DBDE01.ent.ti.com>

Hi Anil,

On 10/18/2012 07:46 AM, AnilKumar, Chimata wrote:
> On Fri, Sep 21, 2012 at 21:19:11, AnilKumar, Chimata wrote:
>> Add tsl2550 ambient light sensor DT data to am335x-evm.dts. In AM335x
>> EVM tsl2550 ambient light sensor is connected to I2C2 bus. So this patch
>> adds child node inside i2c2 node with i2c slave address.
>>
>> TAOS tsl2550 sensor with two-wire SMBus serial interface. This patch
>> also reduces I2C2 clock frequency to 100KHz from 400KHz because the
>> maximum clock frequency of SMBus is 100KHz.
>>
>> Signed-off-by: AnilKumar Ch <anilkumar@ti.com>
>> ---
>>  arch/arm/boot/dts/am335x-evm.dts |    7 ++++++-
>>  1 file changed, 6 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
>> index 3b1f313..d99aa0f 100644
>> --- a/arch/arm/boot/dts/am335x-evm.dts
>> +++ b/arch/arm/boot/dts/am335x-evm.dts
>> @@ -49,7 +49,7 @@
>>  
>>  		i2c2: i2c at 4802a000 {
>>  			status = "okay";
>> -			clock-frequency = <400000>;
>> +			clock-frequency = <100000>;
>>  
>>  			lis331dlh: lis331dlh at 18 {
>>  				compatible = "st,lis331dlh", "st,lis3lv02d";
>> @@ -79,6 +79,11 @@
>>  				st,max-limit-z = <750>;
>>  			};
>>  
>> +			tsl2550: tsl2550 at 39 {
>> +				compatible = "taos,tsl2550";
>> +				reg = <0x39>;
>> +			};
>> +
>>  			tmp275: tmp275 at 48 {
>>  				compatible = "ti,tmp275";
>>  				reg = <0x48>;
> 
> Hi Tony/Benoit,
> 
> If there are no comments in this patch could you please take this in?

Have you updated the binding documentation to list the device?

It should be in:
Documentation/devicetree/bindings/i2c/trivial-devices.txt

Please Cc as well the DT ml.

Regards,
Benoit

^ permalink raw reply

* [PATCH] dma: add new DMA control commands
From: Huang Shijie @ 2012-10-18  7:49 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201210180914.58527.marex@denx.de>

? 2012?10?18? 15:14, Marek Vasut ??:
> Dear Huang Shijie,
>
> Why such massive CC ?
>
>> ? 2012?10?18? 14:18, Vinod Koul ??:
>>> Why cant you do start (prepare clock etc) when you submit the descriptor
>>> to dmaengine. Can be done in tx_submit callback.
>>> Similarly remove the clock when dma transaction gets completed.
>> I ever thought this method too.
>>
>> But it will become low efficient in the following case:
>>
>>     Assuming the gpmi-nand driver has to read out 1024 pages in one
>> _SINGLE_ read operation.
>> The gpmi-nand will submit the descriptor to dmaengine per page.
> It will? Then GPMI NAND is flat our broken ... again.
yes.

Please read the NAND chip spec about the comand READ PAGE(00h-30h) and 
the code
nand_do_read_ops(). The nand chip limits us only read one page out one time.
So the driver will submit the descriptor to dmaengine per page.



>> So with
>> your method,
>> the system will repeat the enable/disable dma clock 1024 time.
> Yes, it is the driver that's wrong.
not the driver.
>> At every
>> enable/disable dma clock,
>> the system has to enable the clock chain and it's parents ...
>>
>> But with this patch, we only need to enable/disable dma clock one time,
>> just at we select the nand chip.
> You are fixing a driver problem at a framework level, wrong.
>
> So, check how the MXS SPI driver handles descriptor chaining. Indeed, the
> Sigmatel screwed the DMA stuff good. But if you analyze the SPI driver, you'll
> notice a few important points that might come handy when you fix the GPMI NAND
> driver properly.
>
> The direction to take here is:
> 1) Implement DMA chaining into the GPMI NAND driver
How can i implement the DMA chain if the nand chip READ-PAGE command 
gives us the one page limit?

thanks
Huang Shijie


> 2) You might need to do one PIO transfer to reconfigure the IP registers between
> each segment of the DMA chain (just as MXS SPI does it)
> 3) You might run out of DMA descriptors when doing too long chains -- so you
> might need to fix that part of the mxs DMA driver.

^ permalink raw reply

* [GIT PULL] Renesas ARM-based SoC defconfig for v3.8
From: Arnd Bergmann @ 2012-10-18  7:29 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20121018005811.GA4325@verge.net.au>

On Thursday 18 October 2012 09:58:11 Simon Horman wrote:
> On Wed, Oct 17, 2012 at 01:42:29PM +0000, Arnd Bergmann wrote:
> > On Wednesday 17 October 2012, Simon Horman wrote:
> > > Hi Olof, Hi Arnd,
> > > 
> > > please consider the following defconfig enhancements for 3.8.
> > 
> > These look good to me, but I wonder what happened to the plan to reduce
> > the number of defconfig files we discussed before. Since you can build
> > a combined kernel that runs on all (or most) of the supported boards,
> > can you add a combined shmobile_defconfig that is able to work on
> > a wide variety of hardware and drop some of the less common defconfig
> > files?
> > 
> > Most of the modern platforms nowadays have just one defconfig that
> > covers everything.
> 
> Hi Arnd,
> 
> I wonder if such consolidation only makes sense for boards that
> make use of DT. If so, I can see that we may be able to come
> up with a single configuration for the Armadillo800eva, KZM9G
> and KZM9D boards. But not for older boards such as the Mackerel which
> have not been converted to use DT.

Usually you should just be able to enable any boards together,
independent of whether they are using DT or not. It's possible
that shmobile does something different from the other platforms
that I'm not aware of, of course. If you look at e.g.
omap2plus_defconfig or imx_v6_v7_defconfig, they both enable
all the available boards.

> I am also wondering if more of the drivers that SH Mobile uses need to
> become DT aware before a consolidated configuration can work.  In
> particular, I am thinking about the SCI serial driver and the location of
> the serial port that can be used for serial console and early printk - this
> features in the kernel command line of the per-board defconfigs and is
> relied on by developers.

Device drivers that don't use DT should get their configuration from
platform_data. The command line can be used to override those, but it's
also normally passed by the boot loader, which also has to configure
e.g. how much memory is present or which uart to use.

	Arnd

^ permalink raw reply

* [PATCH] ARM: SAMSUNG: use devm_ functions for ADC driver
From: Eunki Kim @ 2012-10-18  7:28 UTC (permalink / raw)
  To: linux-arm-kernel

This patch uses devm_* functions for probe function in ADC driver.
It reduces code size and simplifies the code.

Signed-off-by: Eunki Kim <eunki_kim@samsung.com>
---
 arch/arm/plat-samsung/adc.c |   48 +++++++++++-------------------------------
 1 files changed, 13 insertions(+), 35 deletions(-)

diff --git a/arch/arm/plat-samsung/adc.c b/arch/arm/plat-samsung/adc.c
index b1e05cc..37542c2 100644
--- a/arch/arm/plat-samsung/adc.c
+++ b/arch/arm/plat-samsung/adc.c
@@ -344,7 +344,7 @@ static int s3c_adc_probe(struct platform_device *pdev)
 	int ret;
 	unsigned tmp;
 
-	adc = kzalloc(sizeof(struct adc_device), GFP_KERNEL);
+	adc = devm_kzalloc(dev, sizeof(struct adc_device), GFP_KERNEL);
 	if (adc == NULL) {
 		dev_err(dev, "failed to allocate adc_device\n");
 		return -ENOMEM;
@@ -355,50 +355,46 @@ static int s3c_adc_probe(struct platform_device *pdev)
 	adc->pdev = pdev;
 	adc->prescale = S3C2410_ADCCON_PRSCVL(49);
 
-	adc->vdd = regulator_get(dev, "vdd");
+	adc->vdd = devm_regulator_get(dev, "vdd");
 	if (IS_ERR(adc->vdd)) {
 		dev_err(dev, "operating without regulator \"vdd\" .\n");
-		ret = PTR_ERR(adc->vdd);
-		goto err_alloc;
+		return PTR_ERR(adc->vdd);
 	}
 
 	adc->irq = platform_get_irq(pdev, 1);
 	if (adc->irq <= 0) {
 		dev_err(dev, "failed to get adc irq\n");
-		ret = -ENOENT;
-		goto err_reg;
+		return -ENOENT;
 	}
 
-	ret = request_irq(adc->irq, s3c_adc_irq, 0, dev_name(dev), adc);
+	ret = devm_request_irq(dev, adc->irq, s3c_adc_irq, 0, dev_name(dev),
+				adc);
 	if (ret < 0) {
 		dev_err(dev, "failed to attach adc irq\n");
-		goto err_reg;
+		return ret;
 	}
 
-	adc->clk = clk_get(dev, "adc");
+	adc->clk = devm_clk_get(dev, "adc");
 	if (IS_ERR(adc->clk)) {
 		dev_err(dev, "failed to get adc clock\n");
-		ret = PTR_ERR(adc->clk);
-		goto err_irq;
+		return PTR_ERR(adc->clk);
 	}
 
 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!regs) {
 		dev_err(dev, "failed to find registers\n");
-		ret = -ENXIO;
-		goto err_clk;
+		return -ENXIO;
 	}
 
-	adc->regs = ioremap(regs->start, resource_size(regs));
+	adc->regs = devm_request_and_ioremap(dev, regs);
 	if (!adc->regs) {
 		dev_err(dev, "failed to map registers\n");
-		ret = -ENXIO;
-		goto err_clk;
+		return -ENXIO;
 	}
 
 	ret = regulator_enable(adc->vdd);
 	if (ret)
-		goto err_ioremap;
+		return ret;
 
 	clk_enable(adc->clk);
 
@@ -418,32 +414,14 @@ static int s3c_adc_probe(struct platform_device *pdev)
 	adc_dev = adc;
 
 	return 0;
-
- err_ioremap:
-	iounmap(adc->regs);
- err_clk:
-	clk_put(adc->clk);
-
- err_irq:
-	free_irq(adc->irq, adc);
- err_reg:
-	regulator_put(adc->vdd);
- err_alloc:
-	kfree(adc);
-	return ret;
 }
 
 static int __devexit s3c_adc_remove(struct platform_device *pdev)
 {
 	struct adc_device *adc = platform_get_drvdata(pdev);
 
-	iounmap(adc->regs);
-	free_irq(adc->irq, adc);
 	clk_disable(adc->clk);
 	regulator_disable(adc->vdd);
-	regulator_put(adc->vdd);
-	clk_put(adc->clk);
-	kfree(adc);
 
 	return 0;
 }
-- 
1.7.1

^ permalink raw reply related

* IS_ERR_OR_NULL - please STOP telling people to use this on a whim
From: Nicolas Ferre @ 2012-10-18  7:22 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20121017213342.GA28061@n2100.arm.linux.org.uk>

On 10/17/2012 11:33 PM, Russell King - ARM Linux :
> On Wed, Oct 17, 2012 at 11:28:48PM +0300, Phil Carmody wrote:
>> So, what to do? It can and has been used sensibly, so I don't think removing
>> it is the best option.
> 
> Well, the first thing that needs to be done is a full review of every user
> and fixes applied.
> 
> The second thing is that we need eyes on code _and_ review comments, and
> educate those who are telling people to use IS_ERR_OR_NULL() whenever they
> see an IS_ERR() to think about the code a little more - that's kind of the
> purpose of my email.
> 
> Unfortunately, it's going to take time to achieve a change, and if I end
> up being the only one who's spotting these errors, I'm going to get
> incredibly pissed off at doing so (because it will feel like I'm being
> ignored when there's a constant stream of it.)
> 
> Another thing would be to work out whether we can get checkpatch to
> detect usage of IS_ERR_OR_NULL(p) followed by PTR_ERR(p) without any
> explicit NULL checks against p in the same block.  That's probably
> going to be interesting to code up in perl.

True that it would make sense to include in checkpatch to be able to
block code beforehand.
But for sure correction of existing code seems to be a work for Coccinelle.

Best regards,
-- 
Nicolas Ferre

^ permalink raw reply

* [PATCH] dma: add new DMA control commands
From: Marek Vasut @ 2012-10-18  7:14 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <507FA595.4020507@freescale.com>

Dear Huang Shijie,

Why such massive CC ?

> ? 2012?10?18? 14:18, Vinod Koul ??:
> > Why cant you do start (prepare clock etc) when you submit the descriptor
> > to dmaengine. Can be done in tx_submit callback.
> > Similarly remove the clock when dma transaction gets completed.
> 
> I ever thought this method too.
> 
> But it will become low efficient in the following case:
> 
>    Assuming the gpmi-nand driver has to read out 1024 pages in one
> _SINGLE_ read operation.
> The gpmi-nand will submit the descriptor to dmaengine per page.

It will? Then GPMI NAND is flat our broken ... again.

> So with
> your method,
> the system will repeat the enable/disable dma clock 1024 time.

Yes, it is the driver that's wrong.

> At every
> enable/disable dma clock,
> the system has to enable the clock chain and it's parents ...
> 
> But with this patch, we only need to enable/disable dma clock one time,
> just at we select the nand chip.

You are fixing a driver problem at a framework level, wrong.

So, check how the MXS SPI driver handles descriptor chaining. Indeed, the 
Sigmatel screwed the DMA stuff good. But if you analyze the SPI driver, you'll 
notice a few important points that might come handy when you fix the GPMI NAND 
driver properly.

The direction to take here is:
1) Implement DMA chaining into the GPMI NAND driver
2) You might need to do one PIO transfer to reconfigure the IP registers between 
each segment of the DMA chain (just as MXS SPI does it)
3) You might run out of DMA descriptors when doing too long chains -- so you 
might need to fix that part of the mxs DMA driver.

> thanks
> Huang Shijie

Best regards,
Marek Vasut

^ permalink raw reply

* [PATCH 5/5] ARM: OMAP2/3: clockdomain/PRM/CM: move the low-level clockdomain functions into PRM/CM
From: Rajendra Nayak @ 2012-10-18  7:08 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20121015230545.18306.36852.stgit@dusk.lan>

On Tuesday 16 October 2012 04:35 AM, Paul Walmsley wrote:
> Move the low-level SoC-specific clockdomain control functions into
> cm*.c and prm*.c.  For example, OMAP2xxx low-level clockdomain
> functions go into cm2xxx.c.  Then remove the unnecessary
> clockdomain*xxx*.c files.
>
> The objective is to centralize low-level CM and PRM register accesses
> into the cm*.[ch] and prm*.[ch] files, and then to export an OMAP
> SoC-independent API to higher-level OMAP power management code.
>
> Signed-off-by: Paul Walmsley <paul@pwsan.com>
> Cc: Rajendra Nayak <rnayak@ti.com>

Acked-by: Rajendra Nayak <rnayak@ti.com>

> Cc: Vaibhav Hiremath <hvaibhav@ti.com>
> ---
>   arch/arm/mach-omap2/Makefile               |    5
>   arch/arm/mach-omap2/clockdomain2xxx_3xxx.c |  340 ----------------------------
>   arch/arm/mach-omap2/clockdomain33xx.c      |   74 ------
>   arch/arm/mach-omap2/clockdomain44xx.c      |  151 ------------
>   arch/arm/mach-omap2/cm2xxx.c               |   86 +++++++
>   arch/arm/mach-omap2/cm2xxx_3xxx.h          |   12 +
>   arch/arm/mach-omap2/cm33xx.c               |   56 +++++
>   arch/arm/mach-omap2/cm3xxx.c               |  169 ++++++++++++++
>   arch/arm/mach-omap2/cminst44xx.c           |  139 +++++++++++
>   arch/arm/mach-omap2/prm2xxx.c              |   17 +
>   arch/arm/mach-omap2/prm2xxx.h              |    6
>   arch/arm/mach-omap2/prm2xxx_3xxx.c         |   43 ++++
>   arch/arm/mach-omap2/prm2xxx_3xxx.h         |    8 +
>   13 files changed, 536 insertions(+), 570 deletions(-)
>   delete mode 100644 arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
>   delete mode 100644 arch/arm/mach-omap2/clockdomain33xx.c
>   delete mode 100644 arch/arm/mach-omap2/clockdomain44xx.c
>
> diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
> index 56a3386..3751d56 100644
> --- a/arch/arm/mach-omap2/Makefile
> +++ b/arch/arm/mach-omap2/Makefile
> @@ -133,22 +133,17 @@ obj-$(CONFIG_SOC_OMAP5)			+= $(powerdomain-common)
>   # PRCM clockdomain control
>   clockdomain-common			+= clockdomain.o
>   obj-$(CONFIG_ARCH_OMAP2)		+= $(clockdomain-common)
> -obj-$(CONFIG_ARCH_OMAP2)		+= clockdomain2xxx_3xxx.o
>   obj-$(CONFIG_ARCH_OMAP2)		+= clockdomains2xxx_3xxx_data.o
>   obj-$(CONFIG_SOC_OMAP2420)		+= clockdomains2420_data.o
>   obj-$(CONFIG_SOC_OMAP2430)		+= clockdomains2430_data.o
>   obj-$(CONFIG_ARCH_OMAP3)		+= $(clockdomain-common)
> -obj-$(CONFIG_ARCH_OMAP3)		+= clockdomain2xxx_3xxx.o
>   obj-$(CONFIG_ARCH_OMAP3)		+= clockdomains2xxx_3xxx_data.o
>   obj-$(CONFIG_ARCH_OMAP3)		+= clockdomains3xxx_data.o
>   obj-$(CONFIG_ARCH_OMAP4)		+= $(clockdomain-common)
> -obj-$(CONFIG_ARCH_OMAP4)		+= clockdomain44xx.o
>   obj-$(CONFIG_ARCH_OMAP4)		+= clockdomains44xx_data.o
>   obj-$(CONFIG_SOC_AM33XX)		+= $(clockdomain-common)
> -obj-$(CONFIG_SOC_AM33XX)		+= clockdomain33xx.o
>   obj-$(CONFIG_SOC_AM33XX)		+= clockdomains33xx_data.o
>   obj-$(CONFIG_SOC_OMAP5)			+= $(clockdomain-common)
> -obj-$(CONFIG_SOC_OMAP5)			+= clockdomain44xx.o
>
>   # Clock framework
>   obj-$(CONFIG_ARCH_OMAP2)		+= $(clock-common) clock2xxx.o
> diff --git a/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c b/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
> deleted file mode 100644
> index 658487c..0000000
> --- a/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
> +++ /dev/null
> @@ -1,340 +0,0 @@
> -/*
> - * OMAP2 and OMAP3 clockdomain control
> - *
> - * Copyright (C) 2008-2010 Texas Instruments, Inc.
> - * Copyright (C) 2008-2010 Nokia Corporation
> - *
> - * Derived from mach-omap2/clockdomain.c written by Paul Walmsley
> - * Rajendra Nayak <rnayak@ti.com>
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License version 2 as
> - * published by the Free Software Foundation.
> - */
> -
> -#include <linux/types.h>
> -#include <plat/prcm.h>
> -#include "prm.h"
> -#include "prm2xxx_3xxx.h"
> -#include "cm.h"
> -#include "cm2xxx.h"
> -#include "cm3xxx.h"
> -#include "cm-regbits-24xx.h"
> -#include "cm-regbits-34xx.h"
> -#include "prm-regbits-24xx.h"
> -#include "clockdomain.h"
> -
> -static int omap2_clkdm_add_wkdep(struct clockdomain *clkdm1,
> -						struct clockdomain *clkdm2)
> -{
> -	omap2_prm_set_mod_reg_bits((1 << clkdm2->dep_bit),
> -				clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
> -	return 0;
> -}
> -
> -static int omap2_clkdm_del_wkdep(struct clockdomain *clkdm1,
> -						 struct clockdomain *clkdm2)
> -{
> -	omap2_prm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
> -				clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
> -	return 0;
> -}
> -
> -static int omap2_clkdm_read_wkdep(struct clockdomain *clkdm1,
> -						 struct clockdomain *clkdm2)
> -{
> -	return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs,
> -				PM_WKDEP, (1 << clkdm2->dep_bit));
> -}
> -
> -static int omap2_clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
> -{
> -	struct clkdm_dep *cd;
> -	u32 mask = 0;
> -
> -	for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) {
> -		if (!cd->clkdm)
> -			continue; /* only happens if data is erroneous */
> -
> -		/* PRM accesses are slow, so minimize them */
> -		mask |= 1 << cd->clkdm->dep_bit;
> -		atomic_set(&cd->wkdep_usecount, 0);
> -	}
> -
> -	omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
> -				 PM_WKDEP);
> -	return 0;
> -}
> -
> -static int omap3_clkdm_add_sleepdep(struct clockdomain *clkdm1,
> -						 struct clockdomain *clkdm2)
> -{
> -	omap2_cm_set_mod_reg_bits((1 << clkdm2->dep_bit),
> -				clkdm1->pwrdm.ptr->prcm_offs,
> -				OMAP3430_CM_SLEEPDEP);
> -	return 0;
> -}
> -
> -static int omap3_clkdm_del_sleepdep(struct clockdomain *clkdm1,
> -						 struct clockdomain *clkdm2)
> -{
> -	omap2_cm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
> -				clkdm1->pwrdm.ptr->prcm_offs,
> -				OMAP3430_CM_SLEEPDEP);
> -	return 0;
> -}
> -
> -static int omap3_clkdm_read_sleepdep(struct clockdomain *clkdm1,
> -						 struct clockdomain *clkdm2)
> -{
> -	return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs,
> -				OMAP3430_CM_SLEEPDEP, (1 << clkdm2->dep_bit));
> -}
> -
> -static int omap3_clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
> -{
> -	struct clkdm_dep *cd;
> -	u32 mask = 0;
> -
> -	for (cd = clkdm->sleepdep_srcs; cd && cd->clkdm_name; cd++) {
> -		if (!cd->clkdm)
> -			continue; /* only happens if data is erroneous */
> -
> -		/* PRM accesses are slow, so minimize them */
> -		mask |= 1 << cd->clkdm->dep_bit;
> -		atomic_set(&cd->sleepdep_usecount, 0);
> -	}
> -	omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
> -				OMAP3430_CM_SLEEPDEP);
> -	return 0;
> -}
> -
> -static int omap2_clkdm_sleep(struct clockdomain *clkdm)
> -{
> -	omap2_cm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
> -				clkdm->pwrdm.ptr->prcm_offs,
> -				OMAP2_PM_PWSTCTRL);
> -	return 0;
> -}
> -
> -static int omap2_clkdm_wakeup(struct clockdomain *clkdm)
> -{
> -	omap2_cm_clear_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
> -				clkdm->pwrdm.ptr->prcm_offs,
> -				OMAP2_PM_PWSTCTRL);
> -	return 0;
> -}
> -
> -static void omap2_clkdm_allow_idle(struct clockdomain *clkdm)
> -{
> -	if (atomic_read(&clkdm->usecount) > 0)
> -		_clkdm_add_autodeps(clkdm);
> -
> -	omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> -				clkdm->clktrctrl_mask);
> -}
> -
> -static void omap2_clkdm_deny_idle(struct clockdomain *clkdm)
> -{
> -	omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> -				clkdm->clktrctrl_mask);
> -
> -	if (atomic_read(&clkdm->usecount) > 0)
> -		_clkdm_del_autodeps(clkdm);
> -}
> -
> -static void _enable_hwsup(struct clockdomain *clkdm)
> -{
> -	if (cpu_is_omap24xx())
> -		omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> -					       clkdm->clktrctrl_mask);
> -	else if (cpu_is_omap34xx())
> -		omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> -					       clkdm->clktrctrl_mask);
> -}
> -
> -static void _disable_hwsup(struct clockdomain *clkdm)
> -{
> -	if (cpu_is_omap24xx())
> -		omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> -						clkdm->clktrctrl_mask);
> -	else if (cpu_is_omap34xx())
> -		omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> -						clkdm->clktrctrl_mask);
> -}
> -
> -static int omap3_clkdm_sleep(struct clockdomain *clkdm)
> -{
> -	omap3xxx_cm_clkdm_force_sleep(clkdm->pwrdm.ptr->prcm_offs,
> -				clkdm->clktrctrl_mask);
> -	return 0;
> -}
> -
> -static int omap3_clkdm_wakeup(struct clockdomain *clkdm)
> -{
> -	omap3xxx_cm_clkdm_force_wakeup(clkdm->pwrdm.ptr->prcm_offs,
> -				clkdm->clktrctrl_mask);
> -	return 0;
> -}
> -
> -static int omap2xxx_clkdm_clk_enable(struct clockdomain *clkdm)
> -{
> -	bool hwsup = false;
> -
> -	if (!clkdm->clktrctrl_mask)
> -		return 0;
> -
> -	hwsup = omap3xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> -					      clkdm->clktrctrl_mask);
> -
> -	if (hwsup) {
> -		/* Disable HW transitions when we are changing deps */
> -		_disable_hwsup(clkdm);
> -		_clkdm_add_autodeps(clkdm);
> -		_enable_hwsup(clkdm);
> -	} else {
> -		if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
> -			omap2_clkdm_wakeup(clkdm);
> -	}
> -
> -	return 0;
> -}
> -
> -static int omap2xxx_clkdm_clk_disable(struct clockdomain *clkdm)
> -{
> -	bool hwsup = false;
> -
> -	if (!clkdm->clktrctrl_mask)
> -		return 0;
> -
> -	hwsup = omap3xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> -					      clkdm->clktrctrl_mask);
> -
> -	if (hwsup) {
> -		/* Disable HW transitions when we are changing deps */
> -		_disable_hwsup(clkdm);
> -		_clkdm_del_autodeps(clkdm);
> -		_enable_hwsup(clkdm);
> -	} else {
> -		if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP)
> -			omap2_clkdm_sleep(clkdm);
> -	}
> -
> -	return 0;
> -}
> -
> -static void omap3_clkdm_allow_idle(struct clockdomain *clkdm)
> -{
> -	if (atomic_read(&clkdm->usecount) > 0)
> -		_clkdm_add_autodeps(clkdm);
> -
> -	omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> -				clkdm->clktrctrl_mask);
> -}
> -
> -static void omap3_clkdm_deny_idle(struct clockdomain *clkdm)
> -{
> -	omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> -				clkdm->clktrctrl_mask);
> -
> -	if (atomic_read(&clkdm->usecount) > 0)
> -		_clkdm_del_autodeps(clkdm);
> -}
> -
> -static int omap3xxx_clkdm_clk_enable(struct clockdomain *clkdm)
> -{
> -	bool hwsup = false;
> -
> -	if (!clkdm->clktrctrl_mask)
> -		return 0;
> -
> -	/*
> -	 * The CLKDM_MISSING_IDLE_REPORTING flag documentation has
> -	 * more details on the unpleasant problem this is working
> -	 * around
> -	 */
> -	if ((clkdm->flags & CLKDM_MISSING_IDLE_REPORTING) &&
> -	    (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)) {
> -		omap3_clkdm_wakeup(clkdm);
> -		return 0;
> -	}
> -
> -	hwsup = omap2xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> -					      clkdm->clktrctrl_mask);
> -
> -	if (hwsup) {
> -		/* Disable HW transitions when we are changing deps */
> -		_disable_hwsup(clkdm);
> -		_clkdm_add_autodeps(clkdm);
> -		_enable_hwsup(clkdm);
> -	} else {
> -		if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
> -			omap3_clkdm_wakeup(clkdm);
> -	}
> -
> -	return 0;
> -}
> -
> -static int omap3xxx_clkdm_clk_disable(struct clockdomain *clkdm)
> -{
> -	bool hwsup = false;
> -
> -	if (!clkdm->clktrctrl_mask)
> -		return 0;
> -
> -	/*
> -	 * The CLKDM_MISSING_IDLE_REPORTING flag documentation has
> -	 * more details on the unpleasant problem this is working
> -	 * around
> -	 */
> -	if (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING &&
> -	    !(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) {
> -		_enable_hwsup(clkdm);
> -		return 0;
> -	}
> -
> -	hwsup = omap2xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> -					      clkdm->clktrctrl_mask);
> -
> -	if (hwsup) {
> -		/* Disable HW transitions when we are changing deps */
> -		_disable_hwsup(clkdm);
> -		_clkdm_del_autodeps(clkdm);
> -		_enable_hwsup(clkdm);
> -	} else {
> -		if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP)
> -			omap3_clkdm_sleep(clkdm);
> -	}
> -
> -	return 0;
> -}
> -
> -struct clkdm_ops omap2_clkdm_operations = {
> -	.clkdm_add_wkdep	= omap2_clkdm_add_wkdep,
> -	.clkdm_del_wkdep	= omap2_clkdm_del_wkdep,
> -	.clkdm_read_wkdep	= omap2_clkdm_read_wkdep,
> -	.clkdm_clear_all_wkdeps	= omap2_clkdm_clear_all_wkdeps,
> -	.clkdm_sleep		= omap2_clkdm_sleep,
> -	.clkdm_wakeup		= omap2_clkdm_wakeup,
> -	.clkdm_allow_idle	= omap2_clkdm_allow_idle,
> -	.clkdm_deny_idle	= omap2_clkdm_deny_idle,
> -	.clkdm_clk_enable	= omap2xxx_clkdm_clk_enable,
> -	.clkdm_clk_disable	= omap2xxx_clkdm_clk_disable,
> -};
> -
> -struct clkdm_ops omap3_clkdm_operations = {
> -	.clkdm_add_wkdep	= omap2_clkdm_add_wkdep,
> -	.clkdm_del_wkdep	= omap2_clkdm_del_wkdep,
> -	.clkdm_read_wkdep	= omap2_clkdm_read_wkdep,
> -	.clkdm_clear_all_wkdeps	= omap2_clkdm_clear_all_wkdeps,
> -	.clkdm_add_sleepdep	= omap3_clkdm_add_sleepdep,
> -	.clkdm_del_sleepdep	= omap3_clkdm_del_sleepdep,
> -	.clkdm_read_sleepdep	= omap3_clkdm_read_sleepdep,
> -	.clkdm_clear_all_sleepdeps	= omap3_clkdm_clear_all_sleepdeps,
> -	.clkdm_sleep		= omap3_clkdm_sleep,
> -	.clkdm_wakeup		= omap3_clkdm_wakeup,
> -	.clkdm_allow_idle	= omap3_clkdm_allow_idle,
> -	.clkdm_deny_idle	= omap3_clkdm_deny_idle,
> -	.clkdm_clk_enable	= omap3xxx_clkdm_clk_enable,
> -	.clkdm_clk_disable	= omap3xxx_clkdm_clk_disable,
> -};
> diff --git a/arch/arm/mach-omap2/clockdomain33xx.c b/arch/arm/mach-omap2/clockdomain33xx.c
> deleted file mode 100644
> index aca6388..0000000
> --- a/arch/arm/mach-omap2/clockdomain33xx.c
> +++ /dev/null
> @@ -1,74 +0,0 @@
> -/*
> - * AM33XX clockdomain control
> - *
> - * Copyright (C) 2011-2012 Texas Instruments Incorporated - http://www.ti.com/
> - * Vaibhav Hiremath <hvaibhav@ti.com>
> - *
> - * Derived from mach-omap2/clockdomain44xx.c written by Rajendra Nayak
> - *
> - * This program is free software; you can redistribute it and/or
> - * modify it under the terms of the GNU General Public License as
> - * published by the Free Software Foundation version 2.
> - *
> - * This program is distributed "as is" WITHOUT ANY WARRANTY of any
> - * kind, whether express or implied; without even the implied warranty
> - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> - * GNU General Public License for more details.
> - */
> -
> -#include <linux/kernel.h>
> -
> -#include "clockdomain.h"
> -#include "cm33xx.h"
> -
> -
> -static int am33xx_clkdm_sleep(struct clockdomain *clkdm)
> -{
> -	am33xx_cm_clkdm_force_sleep(clkdm->cm_inst, clkdm->clkdm_offs);
> -	return 0;
> -}
> -
> -static int am33xx_clkdm_wakeup(struct clockdomain *clkdm)
> -{
> -	am33xx_cm_clkdm_force_wakeup(clkdm->cm_inst, clkdm->clkdm_offs);
> -	return 0;
> -}
> -
> -static void am33xx_clkdm_allow_idle(struct clockdomain *clkdm)
> -{
> -	am33xx_cm_clkdm_enable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
> -}
> -
> -static void am33xx_clkdm_deny_idle(struct clockdomain *clkdm)
> -{
> -	am33xx_cm_clkdm_disable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
> -}
> -
> -static int am33xx_clkdm_clk_enable(struct clockdomain *clkdm)
> -{
> -	if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
> -		return am33xx_clkdm_wakeup(clkdm);
> -
> -	return 0;
> -}
> -
> -static int am33xx_clkdm_clk_disable(struct clockdomain *clkdm)
> -{
> -	bool hwsup = false;
> -
> -	hwsup = am33xx_cm_is_clkdm_in_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
> -
> -	if (!hwsup && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP))
> -		am33xx_clkdm_sleep(clkdm);
> -
> -	return 0;
> -}
> -
> -struct clkdm_ops am33xx_clkdm_operations = {
> -	.clkdm_sleep		= am33xx_clkdm_sleep,
> -	.clkdm_wakeup		= am33xx_clkdm_wakeup,
> -	.clkdm_allow_idle	= am33xx_clkdm_allow_idle,
> -	.clkdm_deny_idle	= am33xx_clkdm_deny_idle,
> -	.clkdm_clk_enable	= am33xx_clkdm_clk_enable,
> -	.clkdm_clk_disable	= am33xx_clkdm_clk_disable,
> -};
> diff --git a/arch/arm/mach-omap2/clockdomain44xx.c b/arch/arm/mach-omap2/clockdomain44xx.c
> deleted file mode 100644
> index 6fc6155..0000000
> --- a/arch/arm/mach-omap2/clockdomain44xx.c
> +++ /dev/null
> @@ -1,151 +0,0 @@
> -/*
> - * OMAP4 clockdomain control
> - *
> - * Copyright (C) 2008-2010 Texas Instruments, Inc.
> - * Copyright (C) 2008-2010 Nokia Corporation
> - *
> - * Derived from mach-omap2/clockdomain.c written by Paul Walmsley
> - * Rajendra Nayak <rnayak@ti.com>
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License version 2 as
> - * published by the Free Software Foundation.
> - */
> -
> -#include <linux/kernel.h>
> -#include "clockdomain.h"
> -#include "cminst44xx.h"
> -#include "cm44xx.h"
> -
> -static int omap4_clkdm_add_wkup_sleep_dep(struct clockdomain *clkdm1,
> -					struct clockdomain *clkdm2)
> -{
> -	omap4_cminst_set_inst_reg_bits((1 << clkdm2->dep_bit),
> -					clkdm1->prcm_partition,
> -					clkdm1->cm_inst, clkdm1->clkdm_offs +
> -					OMAP4_CM_STATICDEP);
> -	return 0;
> -}
> -
> -static int omap4_clkdm_del_wkup_sleep_dep(struct clockdomain *clkdm1,
> -					struct clockdomain *clkdm2)
> -{
> -	omap4_cminst_clear_inst_reg_bits((1 << clkdm2->dep_bit),
> -					clkdm1->prcm_partition,
> -					clkdm1->cm_inst, clkdm1->clkdm_offs +
> -					OMAP4_CM_STATICDEP);
> -	return 0;
> -}
> -
> -static int omap4_clkdm_read_wkup_sleep_dep(struct clockdomain *clkdm1,
> -					struct clockdomain *clkdm2)
> -{
> -	return omap4_cminst_read_inst_reg_bits(clkdm1->prcm_partition,
> -					clkdm1->cm_inst, clkdm1->clkdm_offs +
> -					OMAP4_CM_STATICDEP,
> -					(1 << clkdm2->dep_bit));
> -}
> -
> -static int omap4_clkdm_clear_all_wkup_sleep_deps(struct clockdomain *clkdm)
> -{
> -	struct clkdm_dep *cd;
> -	u32 mask = 0;
> -
> -	if (!clkdm->prcm_partition)
> -		return 0;
> -
> -	for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) {
> -		if (!cd->clkdm)
> -			continue; /* only happens if data is erroneous */
> -
> -		mask |= 1 << cd->clkdm->dep_bit;
> -		atomic_set(&cd->wkdep_usecount, 0);
> -	}
> -
> -	omap4_cminst_clear_inst_reg_bits(mask, clkdm->prcm_partition,
> -					clkdm->cm_inst, clkdm->clkdm_offs +
> -					OMAP4_CM_STATICDEP);
> -	return 0;
> -}
> -
> -static int omap4_clkdm_sleep(struct clockdomain *clkdm)
> -{
> -	omap4_cminst_clkdm_enable_hwsup(clkdm->prcm_partition,
> -					clkdm->cm_inst, clkdm->clkdm_offs);
> -	return 0;
> -}
> -
> -static int omap4_clkdm_wakeup(struct clockdomain *clkdm)
> -{
> -	omap4_cminst_clkdm_force_wakeup(clkdm->prcm_partition,
> -					clkdm->cm_inst, clkdm->clkdm_offs);
> -	return 0;
> -}
> -
> -static void omap4_clkdm_allow_idle(struct clockdomain *clkdm)
> -{
> -	omap4_cminst_clkdm_enable_hwsup(clkdm->prcm_partition,
> -					clkdm->cm_inst, clkdm->clkdm_offs);
> -}
> -
> -static void omap4_clkdm_deny_idle(struct clockdomain *clkdm)
> -{
> -	if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
> -		omap4_clkdm_wakeup(clkdm);
> -	else
> -		omap4_cminst_clkdm_disable_hwsup(clkdm->prcm_partition,
> -						 clkdm->cm_inst,
> -						 clkdm->clkdm_offs);
> -}
> -
> -static int omap4_clkdm_clk_enable(struct clockdomain *clkdm)
> -{
> -	if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
> -		return omap4_clkdm_wakeup(clkdm);
> -
> -	return 0;
> -}
> -
> -static int omap4_clkdm_clk_disable(struct clockdomain *clkdm)
> -{
> -	bool hwsup = false;
> -
> -	if (!clkdm->prcm_partition)
> -		return 0;
> -
> -	/*
> -	 * The CLKDM_MISSING_IDLE_REPORTING flag documentation has
> -	 * more details on the unpleasant problem this is working
> -	 * around
> -	 */
> -	if (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING &&
> -	    !(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) {
> -		omap4_clkdm_allow_idle(clkdm);
> -		return 0;
> -	}
> -
> -	hwsup = omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition,
> -					clkdm->cm_inst, clkdm->clkdm_offs);
> -
> -	if (!hwsup && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP))
> -		omap4_clkdm_sleep(clkdm);
> -
> -	return 0;
> -}
> -
> -struct clkdm_ops omap4_clkdm_operations = {
> -	.clkdm_add_wkdep	= omap4_clkdm_add_wkup_sleep_dep,
> -	.clkdm_del_wkdep	= omap4_clkdm_del_wkup_sleep_dep,
> -	.clkdm_read_wkdep	= omap4_clkdm_read_wkup_sleep_dep,
> -	.clkdm_clear_all_wkdeps	= omap4_clkdm_clear_all_wkup_sleep_deps,
> -	.clkdm_add_sleepdep	= omap4_clkdm_add_wkup_sleep_dep,
> -	.clkdm_del_sleepdep	= omap4_clkdm_del_wkup_sleep_dep,
> -	.clkdm_read_sleepdep	= omap4_clkdm_read_wkup_sleep_dep,
> -	.clkdm_clear_all_sleepdeps	= omap4_clkdm_clear_all_wkup_sleep_deps,
> -	.clkdm_sleep		= omap4_clkdm_sleep,
> -	.clkdm_wakeup		= omap4_clkdm_wakeup,
> -	.clkdm_allow_idle	= omap4_clkdm_allow_idle,
> -	.clkdm_deny_idle	= omap4_clkdm_deny_idle,
> -	.clkdm_clk_enable	= omap4_clkdm_clk_enable,
> -	.clkdm_clk_disable	= omap4_clkdm_clk_disable,
> -};
> diff --git a/arch/arm/mach-omap2/cm2xxx.c b/arch/arm/mach-omap2/cm2xxx.c
> index 19cee91..0160893 100644
> --- a/arch/arm/mach-omap2/cm2xxx.c
> +++ b/arch/arm/mach-omap2/cm2xxx.c
> @@ -19,9 +19,11 @@
>   #include "soc.h"
>   #include "iomap.h"
>   #include "common.h"
> +#include "prm2xxx.h"
>   #include "cm.h"
>   #include "cm2xxx.h"
>   #include "cm-regbits-24xx.h"
> +#include "clockdomain.h"
>
>   /* CM_AUTOIDLE_PLL.AUTO_* bit values for DPLLs */
>   #define DPLL_AUTOIDLE_DISABLE				0x0
> @@ -165,3 +167,87 @@ int omap2xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift)
>
>   	return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
>   }
> +
> +/* Clockdomain low-level functions */
> +
> +static void omap2xxx_clkdm_allow_idle(struct clockdomain *clkdm)
> +{
> +	if (atomic_read(&clkdm->usecount) > 0)
> +		_clkdm_add_autodeps(clkdm);
> +
> +	omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> +				       clkdm->clktrctrl_mask);
> +}
> +
> +static void omap2xxx_clkdm_deny_idle(struct clockdomain *clkdm)
> +{
> +	omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> +					clkdm->clktrctrl_mask);
> +
> +	if (atomic_read(&clkdm->usecount) > 0)
> +		_clkdm_del_autodeps(clkdm);
> +}
> +
> +static int omap2xxx_clkdm_clk_enable(struct clockdomain *clkdm)
> +{
> +	bool hwsup = false;
> +
> +	if (!clkdm->clktrctrl_mask)
> +		return 0;
> +
> +	hwsup = omap2xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> +					      clkdm->clktrctrl_mask);
> +
> +	if (hwsup) {
> +		/* Disable HW transitions when we are changing deps */
> +		omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> +						clkdm->clktrctrl_mask);
> +		_clkdm_add_autodeps(clkdm);
> +		omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> +					       clkdm->clktrctrl_mask);
> +	} else {
> +		if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
> +			omap2xxx_clkdm_wakeup(clkdm);
> +	}
> +
> +	return 0;
> +}
> +
> +static int omap2xxx_clkdm_clk_disable(struct clockdomain *clkdm)
> +{
> +	bool hwsup = false;
> +
> +	if (!clkdm->clktrctrl_mask)
> +		return 0;
> +
> +	hwsup = omap2xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> +					      clkdm->clktrctrl_mask);
> +
> +	if (hwsup) {
> +		/* Disable HW transitions when we are changing deps */
> +		omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> +						clkdm->clktrctrl_mask);
> +		_clkdm_del_autodeps(clkdm);
> +		omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> +					       clkdm->clktrctrl_mask);
> +	} else {
> +		if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP)
> +			omap2xxx_clkdm_sleep(clkdm);
> +	}
> +
> +	return 0;
> +}
> +
> +struct clkdm_ops omap2_clkdm_operations = {
> +	.clkdm_add_wkdep	= omap2_clkdm_add_wkdep,
> +	.clkdm_del_wkdep	= omap2_clkdm_del_wkdep,
> +	.clkdm_read_wkdep	= omap2_clkdm_read_wkdep,
> +	.clkdm_clear_all_wkdeps	= omap2_clkdm_clear_all_wkdeps,
> +	.clkdm_sleep		= omap2xxx_clkdm_sleep,
> +	.clkdm_wakeup		= omap2xxx_clkdm_wakeup,
> +	.clkdm_allow_idle	= omap2xxx_clkdm_allow_idle,
> +	.clkdm_deny_idle	= omap2xxx_clkdm_deny_idle,
> +	.clkdm_clk_enable	= omap2xxx_clkdm_clk_enable,
> +	.clkdm_clk_disable	= omap2xxx_clkdm_clk_disable,
> +};
> +
> diff --git a/arch/arm/mach-omap2/cm2xxx_3xxx.h b/arch/arm/mach-omap2/cm2xxx_3xxx.h
> index 64df725..78c218c 100644
> --- a/arch/arm/mach-omap2/cm2xxx_3xxx.h
> +++ b/arch/arm/mach-omap2/cm2xxx_3xxx.h
> @@ -73,6 +73,18 @@ static inline u32 omap2_cm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module,
>   	return v;
>   }
>
> +/* Read a CM register, AND it, and shift the result down to bit 0 */
> +static inline u32 omap2_cm_read_mod_bits_shift(s16 domain, s16 idx, u32 mask)
> +{
> +	u32 v;
> +
> +	v = omap2_cm_read_mod_reg(domain, idx);
> +	v &= mask;
> +	v >>= __ffs(mask);
> +
> +	return v;
> +}
> +
>   static inline u32 omap2_cm_set_mod_reg_bits(u32 bits, s16 module, s16 idx)
>   {
>   	return omap2_cm_rmw_mod_reg_bits(bits, bits, module, idx);
> diff --git a/arch/arm/mach-omap2/cm33xx.c b/arch/arm/mach-omap2/cm33xx.c
> index 13f56ea..9b3bcff1 100644
> --- a/arch/arm/mach-omap2/cm33xx.c
> +++ b/arch/arm/mach-omap2/cm33xx.c
> @@ -24,6 +24,7 @@
>
>   #include <plat/common.h>
>
> +#include "clockdomain.h"
>   #include "cm.h"
>   #include "cm33xx.h"
>   #include "cm-regbits-34xx.h"
> @@ -311,3 +312,58 @@ void am33xx_cm_module_disable(u16 inst, s16 cdoffs, u16 clkctrl_offs)
>   	v &= ~AM33XX_MODULEMODE_MASK;
>   	am33xx_cm_write_reg(v, inst, clkctrl_offs);
>   }
> +
> +/*
> + * Clockdomain low-level functions
> + */
> +
> +static int am33xx_clkdm_sleep(struct clockdomain *clkdm)
> +{
> +	am33xx_cm_clkdm_force_sleep(clkdm->cm_inst, clkdm->clkdm_offs);
> +	return 0;
> +}
> +
> +static int am33xx_clkdm_wakeup(struct clockdomain *clkdm)
> +{
> +	am33xx_cm_clkdm_force_wakeup(clkdm->cm_inst, clkdm->clkdm_offs);
> +	return 0;
> +}
> +
> +static void am33xx_clkdm_allow_idle(struct clockdomain *clkdm)
> +{
> +	am33xx_cm_clkdm_enable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
> +}
> +
> +static void am33xx_clkdm_deny_idle(struct clockdomain *clkdm)
> +{
> +	am33xx_cm_clkdm_disable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
> +}
> +
> +static int am33xx_clkdm_clk_enable(struct clockdomain *clkdm)
> +{
> +	if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
> +		return am33xx_clkdm_wakeup(clkdm);
> +
> +	return 0;
> +}
> +
> +static int am33xx_clkdm_clk_disable(struct clockdomain *clkdm)
> +{
> +	bool hwsup = false;
> +
> +	hwsup = am33xx_cm_is_clkdm_in_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
> +
> +	if (!hwsup && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP))
> +		am33xx_clkdm_sleep(clkdm);
> +
> +	return 0;
> +}
> +
> +struct clkdm_ops am33xx_clkdm_operations = {
> +	.clkdm_sleep		= am33xx_clkdm_sleep,
> +	.clkdm_wakeup		= am33xx_clkdm_wakeup,
> +	.clkdm_allow_idle	= am33xx_clkdm_allow_idle,
> +	.clkdm_deny_idle	= am33xx_clkdm_deny_idle,
> +	.clkdm_clk_enable	= am33xx_clkdm_clk_enable,
> +	.clkdm_clk_disable	= am33xx_clkdm_clk_disable,
> +};
> diff --git a/arch/arm/mach-omap2/cm3xxx.c b/arch/arm/mach-omap2/cm3xxx.c
> index 075cabe..3493fef 100644
> --- a/arch/arm/mach-omap2/cm3xxx.c
> +++ b/arch/arm/mach-omap2/cm3xxx.c
> @@ -19,9 +19,11 @@
>   #include "soc.h"
>   #include "iomap.h"
>   #include "common.h"
> +#include "prm2xxx_3xxx.h"
>   #include "cm.h"
>   #include "cm3xxx.h"
>   #include "cm-regbits-34xx.h"
> +#include "clockdomain.h"
>
>   static const u8 omap3xxx_cm_idlest_offs[] = { CM_IDLEST1, CM_IDLEST2 };
>
> @@ -104,6 +106,173 @@ int omap3xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift)
>   	return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
>   }
>
> +/* Clockdomain low-level operations */
> +
> +static int omap3xxx_clkdm_add_sleepdep(struct clockdomain *clkdm1,
> +				       struct clockdomain *clkdm2)
> +{
> +	omap2_cm_set_mod_reg_bits((1 << clkdm2->dep_bit),
> +				  clkdm1->pwrdm.ptr->prcm_offs,
> +				  OMAP3430_CM_SLEEPDEP);
> +	return 0;
> +}
> +
> +static int omap3xxx_clkdm_del_sleepdep(struct clockdomain *clkdm1,
> +				       struct clockdomain *clkdm2)
> +{
> +	omap2_cm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
> +				    clkdm1->pwrdm.ptr->prcm_offs,
> +				    OMAP3430_CM_SLEEPDEP);
> +	return 0;
> +}
> +
> +static int omap3xxx_clkdm_read_sleepdep(struct clockdomain *clkdm1,
> +					struct clockdomain *clkdm2)
> +{
> +	return omap2_cm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs,
> +					    OMAP3430_CM_SLEEPDEP,
> +					    (1 << clkdm2->dep_bit));
> +}
> +
> +static int omap3xxx_clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
> +{
> +	struct clkdm_dep *cd;
> +	u32 mask = 0;
> +
> +	for (cd = clkdm->sleepdep_srcs; cd && cd->clkdm_name; cd++) {
> +		if (!cd->clkdm)
> +			continue; /* only happens if data is erroneous */
> +
> +		mask |= 1 << cd->clkdm->dep_bit;
> +		atomic_set(&cd->sleepdep_usecount, 0);
> +	}
> +	omap2_cm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
> +				    OMAP3430_CM_SLEEPDEP);
> +	return 0;
> +}
> +
> +static int omap3xxx_clkdm_sleep(struct clockdomain *clkdm)
> +{
> +	omap3xxx_cm_clkdm_force_sleep(clkdm->pwrdm.ptr->prcm_offs,
> +				      clkdm->clktrctrl_mask);
> +	return 0;
> +}
> +
> +static int omap3xxx_clkdm_wakeup(struct clockdomain *clkdm)
> +{
> +	omap3xxx_cm_clkdm_force_wakeup(clkdm->pwrdm.ptr->prcm_offs,
> +				       clkdm->clktrctrl_mask);
> +	return 0;
> +}
> +
> +static void omap3xxx_clkdm_allow_idle(struct clockdomain *clkdm)
> +{
> +	if (atomic_read(&clkdm->usecount) > 0)
> +		_clkdm_add_autodeps(clkdm);
> +
> +	omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> +				       clkdm->clktrctrl_mask);
> +}
> +
> +static void omap3xxx_clkdm_deny_idle(struct clockdomain *clkdm)
> +{
> +	omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> +					clkdm->clktrctrl_mask);
> +
> +	if (atomic_read(&clkdm->usecount) > 0)
> +		_clkdm_del_autodeps(clkdm);
> +}
> +
> +static int omap3xxx_clkdm_clk_enable(struct clockdomain *clkdm)
> +{
> +	bool hwsup = false;
> +
> +	if (!clkdm->clktrctrl_mask)
> +		return 0;
> +
> +	/*
> +	 * The CLKDM_MISSING_IDLE_REPORTING flag documentation has
> +	 * more details on the unpleasant problem this is working
> +	 * around
> +	 */
> +	if ((clkdm->flags & CLKDM_MISSING_IDLE_REPORTING) &&
> +	    (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)) {
> +		omap3xxx_clkdm_wakeup(clkdm);
> +		return 0;
> +	}
> +
> +	hwsup = omap3xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> +					      clkdm->clktrctrl_mask);
> +
> +	if (hwsup) {
> +		/* Disable HW transitions when we are changing deps */
> +		omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> +						clkdm->clktrctrl_mask);
> +		_clkdm_add_autodeps(clkdm);
> +		omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> +					       clkdm->clktrctrl_mask);
> +	} else {
> +		if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
> +			omap3xxx_clkdm_wakeup(clkdm);
> +	}
> +
> +	return 0;
> +}
> +
> +static int omap3xxx_clkdm_clk_disable(struct clockdomain *clkdm)
> +{
> +	bool hwsup = false;
> +
> +	if (!clkdm->clktrctrl_mask)
> +		return 0;
> +
> +	/*
> +	 * The CLKDM_MISSING_IDLE_REPORTING flag documentation has
> +	 * more details on the unpleasant problem this is working
> +	 * around
> +	 */
> +	if (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING &&
> +	    !(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) {
> +		omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> +					       clkdm->clktrctrl_mask);
> +		return 0;
> +	}
> +
> +	hwsup = omap3xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> +					      clkdm->clktrctrl_mask);
> +
> +	if (hwsup) {
> +		/* Disable HW transitions when we are changing deps */
> +		omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> +						clkdm->clktrctrl_mask);
> +		_clkdm_del_autodeps(clkdm);
> +		omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
> +					       clkdm->clktrctrl_mask);
> +	} else {
> +		if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP)
> +			omap3xxx_clkdm_sleep(clkdm);
> +	}
> +
> +	return 0;
> +}
> +
> +struct clkdm_ops omap3_clkdm_operations = {
> +	.clkdm_add_wkdep	= omap2_clkdm_add_wkdep,
> +	.clkdm_del_wkdep	= omap2_clkdm_del_wkdep,
> +	.clkdm_read_wkdep	= omap2_clkdm_read_wkdep,
> +	.clkdm_clear_all_wkdeps	= omap2_clkdm_clear_all_wkdeps,
> +	.clkdm_add_sleepdep	= omap3xxx_clkdm_add_sleepdep,
> +	.clkdm_del_sleepdep	= omap3xxx_clkdm_del_sleepdep,
> +	.clkdm_read_sleepdep	= omap3xxx_clkdm_read_sleepdep,
> +	.clkdm_clear_all_sleepdeps	= omap3xxx_clkdm_clear_all_sleepdeps,
> +	.clkdm_sleep		= omap3xxx_clkdm_sleep,
> +	.clkdm_wakeup		= omap3xxx_clkdm_wakeup,
> +	.clkdm_allow_idle	= omap3xxx_clkdm_allow_idle,
> +	.clkdm_deny_idle	= omap3xxx_clkdm_deny_idle,
> +	.clkdm_clk_enable	= omap3xxx_clkdm_clk_enable,
> +	.clkdm_clk_disable	= omap3xxx_clkdm_clk_disable,
> +};
> +
>   /*
>    * Context save/restore code - OMAP3 only
>    */
> diff --git a/arch/arm/mach-omap2/cminst44xx.c b/arch/arm/mach-omap2/cminst44xx.c
> index 1894015..9dca0ee 100644
> --- a/arch/arm/mach-omap2/cminst44xx.c
> +++ b/arch/arm/mach-omap2/cminst44xx.c
> @@ -22,6 +22,7 @@
>
>   #include "iomap.h"
>   #include "common.h"
> +#include "clockdomain.h"
>   #include "cm.h"
>   #include "cm1_44xx.h"
>   #include "cm2_44xx.h"
> @@ -343,3 +344,141 @@ void omap4_cminst_module_disable(u8 part, u16 inst, s16 cdoffs,
>   	v &= ~OMAP4430_MODULEMODE_MASK;
>   	omap4_cminst_write_inst_reg(v, part, inst, clkctrl_offs);
>   }
> +
> +/*
> + * Clockdomain low-level functions
> + */
> +
> +static int omap4_clkdm_add_wkup_sleep_dep(struct clockdomain *clkdm1,
> +					struct clockdomain *clkdm2)
> +{
> +	omap4_cminst_set_inst_reg_bits((1 << clkdm2->dep_bit),
> +				       clkdm1->prcm_partition,
> +				       clkdm1->cm_inst, clkdm1->clkdm_offs +
> +				       OMAP4_CM_STATICDEP);
> +	return 0;
> +}
> +
> +static int omap4_clkdm_del_wkup_sleep_dep(struct clockdomain *clkdm1,
> +					struct clockdomain *clkdm2)
> +{
> +	omap4_cminst_clear_inst_reg_bits((1 << clkdm2->dep_bit),
> +					 clkdm1->prcm_partition,
> +					 clkdm1->cm_inst, clkdm1->clkdm_offs +
> +					 OMAP4_CM_STATICDEP);
> +	return 0;
> +}
> +
> +static int omap4_clkdm_read_wkup_sleep_dep(struct clockdomain *clkdm1,
> +					struct clockdomain *clkdm2)
> +{
> +	return omap4_cminst_read_inst_reg_bits(clkdm1->prcm_partition,
> +					       clkdm1->cm_inst,
> +					       clkdm1->clkdm_offs +
> +					       OMAP4_CM_STATICDEP,
> +					       (1 << clkdm2->dep_bit));
> +}
> +
> +static int omap4_clkdm_clear_all_wkup_sleep_deps(struct clockdomain *clkdm)
> +{
> +	struct clkdm_dep *cd;
> +	u32 mask = 0;
> +
> +	if (!clkdm->prcm_partition)
> +		return 0;
> +
> +	for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) {
> +		if (!cd->clkdm)
> +			continue; /* only happens if data is erroneous */
> +
> +		mask |= 1 << cd->clkdm->dep_bit;
> +		atomic_set(&cd->wkdep_usecount, 0);
> +	}
> +
> +	omap4_cminst_clear_inst_reg_bits(mask, clkdm->prcm_partition,
> +					 clkdm->cm_inst, clkdm->clkdm_offs +
> +					 OMAP4_CM_STATICDEP);
> +	return 0;
> +}
> +
> +static int omap4_clkdm_sleep(struct clockdomain *clkdm)
> +{
> +	omap4_cminst_clkdm_enable_hwsup(clkdm->prcm_partition,
> +					clkdm->cm_inst, clkdm->clkdm_offs);
> +	return 0;
> +}
> +
> +static int omap4_clkdm_wakeup(struct clockdomain *clkdm)
> +{
> +	omap4_cminst_clkdm_force_wakeup(clkdm->prcm_partition,
> +					clkdm->cm_inst, clkdm->clkdm_offs);
> +	return 0;
> +}
> +
> +static void omap4_clkdm_allow_idle(struct clockdomain *clkdm)
> +{
> +	omap4_cminst_clkdm_enable_hwsup(clkdm->prcm_partition,
> +					clkdm->cm_inst, clkdm->clkdm_offs);
> +}
> +
> +static void omap4_clkdm_deny_idle(struct clockdomain *clkdm)
> +{
> +	if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
> +		omap4_clkdm_wakeup(clkdm);
> +	else
> +		omap4_cminst_clkdm_disable_hwsup(clkdm->prcm_partition,
> +						 clkdm->cm_inst,
> +						 clkdm->clkdm_offs);
> +}
> +
> +static int omap4_clkdm_clk_enable(struct clockdomain *clkdm)
> +{
> +	if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
> +		return omap4_clkdm_wakeup(clkdm);
> +
> +	return 0;
> +}
> +
> +static int omap4_clkdm_clk_disable(struct clockdomain *clkdm)
> +{
> +	bool hwsup = false;
> +
> +	if (!clkdm->prcm_partition)
> +		return 0;
> +
> +	/*
> +	 * The CLKDM_MISSING_IDLE_REPORTING flag documentation has
> +	 * more details on the unpleasant problem this is working
> +	 * around
> +	 */
> +	if (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING &&
> +	    !(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) {
> +		omap4_clkdm_allow_idle(clkdm);
> +		return 0;
> +	}
> +
> +	hwsup = omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition,
> +					clkdm->cm_inst, clkdm->clkdm_offs);
> +
> +	if (!hwsup && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP))
> +		omap4_clkdm_sleep(clkdm);
> +
> +	return 0;
> +}
> +
> +struct clkdm_ops omap4_clkdm_operations = {
> +	.clkdm_add_wkdep	= omap4_clkdm_add_wkup_sleep_dep,
> +	.clkdm_del_wkdep	= omap4_clkdm_del_wkup_sleep_dep,
> +	.clkdm_read_wkdep	= omap4_clkdm_read_wkup_sleep_dep,
> +	.clkdm_clear_all_wkdeps	= omap4_clkdm_clear_all_wkup_sleep_deps,
> +	.clkdm_add_sleepdep	= omap4_clkdm_add_wkup_sleep_dep,
> +	.clkdm_del_sleepdep	= omap4_clkdm_del_wkup_sleep_dep,
> +	.clkdm_read_sleepdep	= omap4_clkdm_read_wkup_sleep_dep,
> +	.clkdm_clear_all_sleepdeps	= omap4_clkdm_clear_all_wkup_sleep_deps,
> +	.clkdm_sleep		= omap4_clkdm_sleep,
> +	.clkdm_wakeup		= omap4_clkdm_wakeup,
> +	.clkdm_allow_idle	= omap4_clkdm_allow_idle,
> +	.clkdm_deny_idle	= omap4_clkdm_deny_idle,
> +	.clkdm_clk_enable	= omap4_clkdm_clk_enable,
> +	.clkdm_clk_disable	= omap4_clkdm_clk_disable,
> +};
> diff --git a/arch/arm/mach-omap2/prm2xxx.c b/arch/arm/mach-omap2/prm2xxx.c
> index 14940c4..d08a2b9 100644
> --- a/arch/arm/mach-omap2/prm2xxx.c
> +++ b/arch/arm/mach-omap2/prm2xxx.c
> @@ -23,10 +23,27 @@
>
>   #include "vp.h"
>   #include "powerdomain.h"
> +#include "clockdomain.h"
>   #include "prm2xxx.h"
>   #include "cm2xxx_3xxx.h"
>   #include "prm-regbits-24xx.h"
>
> +int omap2xxx_clkdm_sleep(struct clockdomain *clkdm)
> +{
> +	omap2_prm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
> +				   clkdm->pwrdm.ptr->prcm_offs,
> +				   OMAP2_PM_PWSTCTRL);
> +	return 0;
> +}
> +
> +int omap2xxx_clkdm_wakeup(struct clockdomain *clkdm)
> +{
> +	omap2_prm_clear_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
> +				     clkdm->pwrdm.ptr->prcm_offs,
> +				     OMAP2_PM_PWSTCTRL);
> +	return 0;
> +}
> +
>   struct pwrdm_ops omap2_pwrdm_operations = {
>   	.pwrdm_set_next_pwrst	= omap2_pwrdm_set_next_pwrst,
>   	.pwrdm_read_next_pwrst	= omap2_pwrdm_read_next_pwrst,
> diff --git a/arch/arm/mach-omap2/prm2xxx.h b/arch/arm/mach-omap2/prm2xxx.h
> index 6490e1a..6d76716 100644
> --- a/arch/arm/mach-omap2/prm2xxx.h
> +++ b/arch/arm/mach-omap2/prm2xxx.h
> @@ -119,4 +119,10 @@
>   #define OMAP24XX_PRCM_IRQSTATUS_IVA			0x00f8
>   #define OMAP24XX_PRCM_IRQENABLE_IVA			0x00fc
>
> +#ifndef __ASSEMBLER__
> +/* Function prototypes */
> +extern int omap2xxx_clkdm_sleep(struct clockdomain *clkdm);
> +extern int omap2xxx_clkdm_wakeup(struct clockdomain *clkdm);
> +#endif
> +
>   #endif
> diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c
> index bdddf5c..30517f5 100644
> --- a/arch/arm/mach-omap2/prm2xxx_3xxx.c
> +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c
> @@ -20,6 +20,7 @@
>   #include "powerdomain.h"
>   #include "prm2xxx_3xxx.h"
>   #include "prm-regbits-24xx.h"
> +#include "clockdomain.h"
>
>   /**
>    * omap2_prm_is_hardreset_asserted - read the HW reset line state of
> @@ -208,3 +209,45 @@ int omap2_pwrdm_wait_transition(struct powerdomain *pwrdm)
>   	return 0;
>   }
>
> +int omap2_clkdm_add_wkdep(struct clockdomain *clkdm1,
> +			  struct clockdomain *clkdm2)
> +{
> +	omap2_prm_set_mod_reg_bits((1 << clkdm2->dep_bit),
> +				   clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
> +	return 0;
> +}
> +
> +int omap2_clkdm_del_wkdep(struct clockdomain *clkdm1,
> +			  struct clockdomain *clkdm2)
> +{
> +	omap2_prm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
> +				     clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
> +	return 0;
> +}
> +
> +int omap2_clkdm_read_wkdep(struct clockdomain *clkdm1,
> +			   struct clockdomain *clkdm2)
> +{
> +	return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs,
> +					     PM_WKDEP, (1 << clkdm2->dep_bit));
> +}
> +
> +int omap2_clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
> +{
> +	struct clkdm_dep *cd;
> +	u32 mask = 0;
> +
> +	for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) {
> +		if (!cd->clkdm)
> +			continue; /* only happens if data is erroneous */
> +
> +		/* PRM accesses are slow, so minimize them */
> +		mask |= 1 << cd->clkdm->dep_bit;
> +		atomic_set(&cd->wkdep_usecount, 0);
> +	}
> +
> +	omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
> +				     PM_WKDEP);
> +	return 0;
> +}
> +
> diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.h b/arch/arm/mach-omap2/prm2xxx_3xxx.h
> index 706b026..22a405a 100644
> --- a/arch/arm/mach-omap2/prm2xxx_3xxx.h
> +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.h
> @@ -116,6 +116,14 @@ extern int omap2_pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank);
>   extern int omap2_pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst);
>   extern int omap2_pwrdm_wait_transition(struct powerdomain *pwrdm);
>
> +extern int omap2_clkdm_add_wkdep(struct clockdomain *clkdm1,
> +				 struct clockdomain *clkdm2);
> +extern int omap2_clkdm_del_wkdep(struct clockdomain *clkdm1,
> +				 struct clockdomain *clkdm2);
> +extern int omap2_clkdm_read_wkdep(struct clockdomain *clkdm1,
> +				  struct clockdomain *clkdm2);
> +extern int omap2_clkdm_clear_all_wkdeps(struct clockdomain *clkdm);
> +
>   #endif /* __ASSEMBLER */
>
>   /*
>
>

^ permalink raw reply

* [PATCH 3/5] ARM: OMAP2+: powerdomain/PRM: move the low-level powerdomain functions into PRM
From: Rajendra Nayak @ 2012-10-18  7:08 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20121015230542.18306.88940.stgit@dusk.lan>

On Tuesday 16 October 2012 04:35 AM, Paul Walmsley wrote:
> Move the low-level SoC-specific powerdomain control functions into
> prm*.c.  For example, OMAP2xxx low-level powerdomain functions go into
> prm2xxx.c.  Then remove the unnecessary powerdomain*xxx*.c files.
>
> The objective is to centralize low-level PRM register accesses into
> the prm*.[ch] files, and then to export an OMAP SoC-independent API to
> higher-level OMAP power management code.
>
> Signed-off-by: Paul Walmsley <paul@pwsan.com>
> Cc: Rajendra Nayak <rnayak@ti.com>

Acked-by: Rajendra Nayak <rnayak@ti.com>

> Cc: Vaibhav Hiremath <hvaibhav@ti.com>
> ---
>   arch/arm/mach-omap2/Makefile               |    1
>   arch/arm/mach-omap2/powerdomain2xxx_3xxx.c |  242 ------------------------
>   arch/arm/mach-omap2/powerdomain33xx.c      |  229 ----------------------
>   arch/arm/mach-omap2/powerdomain44xx.c      |  285 ----------------------------
>   arch/arm/mach-omap2/prm2xxx.c              |   40 ++++
>   arch/arm/mach-omap2/prm2xxx_3xxx.c         |  112 +++++++++++
>   arch/arm/mach-omap2/prm2xxx_3xxx.h         |   13 +
>   arch/arm/mach-omap2/prm33xx.c              |  202 ++++++++++++++++++++
>   arch/arm/mach-omap2/prm3xxx.c              |  106 ++++++++++
>   arch/arm/mach-omap2/prm44xx.c              |  264 ++++++++++++++++++++++++++
>   10 files changed, 736 insertions(+), 758 deletions(-)
>   delete mode 100644 arch/arm/mach-omap2/powerdomain2xxx_3xxx.c
>   delete mode 100644 arch/arm/mach-omap2/powerdomain33xx.c
>   delete mode 100644 arch/arm/mach-omap2/powerdomain44xx.c
>   create mode 100644 arch/arm/mach-omap2/prm2xxx.c
>
> diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
> index 20849604..7404e3d 100644
> --- a/arch/arm/mach-omap2/Makefile
> +++ b/arch/arm/mach-omap2/Makefile
> @@ -95,6 +95,7 @@ endif
>   # PRCM
>   obj-y					+= prcm.o prm_common.o
>   obj-$(CONFIG_ARCH_OMAP2)		+= cm2xxx_3xxx.o prm2xxx_3xxx.o
> +obj-$(CONFIG_ARCH_OMAP2)		+= prm2xxx.o
>   obj-$(CONFIG_ARCH_OMAP3)		+= cm2xxx_3xxx.o prm2xxx_3xxx.o
>   obj-$(CONFIG_ARCH_OMAP3)		+= prm3xxx.o
>   obj-$(CONFIG_ARCH_OMAP3)		+= vc3xxx_data.o vp3xxx_data.o
> diff --git a/arch/arm/mach-omap2/powerdomain2xxx_3xxx.c b/arch/arm/mach-omap2/powerdomain2xxx_3xxx.c
> deleted file mode 100644
> index 3950ccf..0000000
> --- a/arch/arm/mach-omap2/powerdomain2xxx_3xxx.c
> +++ /dev/null
> @@ -1,242 +0,0 @@
> -/*
> - * OMAP2 and OMAP3 powerdomain control
> - *
> - * Copyright (C) 2009-2011 Texas Instruments, Inc.
> - * Copyright (C) 2007-2009 Nokia Corporation
> - *
> - * Derived from mach-omap2/powerdomain.c written by Paul Walmsley
> - * Rajendra Nayak <rnayak@ti.com>
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License version 2 as
> - * published by the Free Software Foundation.
> - */
> -
> -#include <linux/io.h>
> -#include <linux/errno.h>
> -#include <linux/delay.h>
> -#include <linux/bug.h>
> -
> -#include <plat/prcm.h>
> -
> -#include "powerdomain.h"
> -#include "prm.h"
> -#include "prm-regbits-24xx.h"
> -#include "prm-regbits-34xx.h"
> -
> -
> -/* Common functions across OMAP2 and OMAP3 */
> -static int omap2_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
> -{
> -	omap2_prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK,
> -				(pwrst << OMAP_POWERSTATE_SHIFT),
> -				pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL);
> -	return 0;
> -}
> -
> -static int omap2_pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
> -{
> -	return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
> -					     OMAP2_PM_PWSTCTRL,
> -					     OMAP_POWERSTATE_MASK);
> -}
> -
> -static int omap2_pwrdm_read_pwrst(struct powerdomain *pwrdm)
> -{
> -	return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
> -					     OMAP2_PM_PWSTST,
> -					     OMAP_POWERSTATEST_MASK);
> -}
> -
> -static int omap2_pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank,
> -								u8 pwrst)
> -{
> -	u32 m;
> -
> -	m = omap2_pwrdm_get_mem_bank_onstate_mask(bank);
> -
> -	omap2_prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)), pwrdm->prcm_offs,
> -				   OMAP2_PM_PWSTCTRL);
> -
> -	return 0;
> -}
> -
> -static int omap2_pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank,
> -								u8 pwrst)
> -{
> -	u32 m;
> -
> -	m = omap2_pwrdm_get_mem_bank_retst_mask(bank);
> -
> -	omap2_prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)), pwrdm->prcm_offs,
> -				   OMAP2_PM_PWSTCTRL);
> -
> -	return 0;
> -}
> -
> -static int omap2_pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
> -{
> -	u32 m;
> -
> -	m = omap2_pwrdm_get_mem_bank_stst_mask(bank);
> -
> -	return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, OMAP2_PM_PWSTST,
> -					     m);
> -}
> -
> -static int omap2_pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank)
> -{
> -	u32 m;
> -
> -	m = omap2_pwrdm_get_mem_bank_retst_mask(bank);
> -
> -	return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
> -					     OMAP2_PM_PWSTCTRL, m);
> -}
> -
> -static int omap2_pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
> -{
> -	u32 v;
> -
> -	v = pwrst << __ffs(OMAP3430_LOGICL1CACHERETSTATE_MASK);
> -	omap2_prm_rmw_mod_reg_bits(OMAP3430_LOGICL1CACHERETSTATE_MASK, v,
> -				   pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL);
> -
> -	return 0;
> -}
> -
> -static int omap2_pwrdm_wait_transition(struct powerdomain *pwrdm)
> -{
> -	u32 c = 0;
> -
> -	/*
> -	 * REVISIT: pwrdm_wait_transition() may be better implemented
> -	 * via a callback and a periodic timer check -- how long do we expect
> -	 * powerdomain transitions to take?
> -	 */
> -
> -	/* XXX Is this udelay() value meaningful? */
> -	while ((omap2_prm_read_mod_reg(pwrdm->prcm_offs, OMAP2_PM_PWSTST) &
> -		OMAP_INTRANSITION_MASK) &&
> -		(c++ < PWRDM_TRANSITION_BAILOUT))
> -			udelay(1);
> -
> -	if (c > PWRDM_TRANSITION_BAILOUT) {
> -		pr_err("powerdomain: %s: waited too long to complete transition\n",
> -		       pwrdm->name);
> -		return -EAGAIN;
> -	}
> -
> -	pr_debug("powerdomain: completed transition in %d loops\n", c);
> -
> -	return 0;
> -}
> -
> -/* Applicable only for OMAP3. Not supported on OMAP2 */
> -static int omap3_pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
> -{
> -	return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
> -					     OMAP3430_PM_PREPWSTST,
> -					     OMAP3430_LASTPOWERSTATEENTERED_MASK);
> -}
> -
> -static int omap3_pwrdm_read_logic_pwrst(struct powerdomain *pwrdm)
> -{
> -	return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
> -					     OMAP2_PM_PWSTST,
> -					     OMAP3430_LOGICSTATEST_MASK);
> -}
> -
> -static int omap3_pwrdm_read_logic_retst(struct powerdomain *pwrdm)
> -{
> -	return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
> -					     OMAP2_PM_PWSTCTRL,
> -					     OMAP3430_LOGICSTATEST_MASK);
> -}
> -
> -static int omap3_pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm)
> -{
> -	return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
> -					     OMAP3430_PM_PREPWSTST,
> -					     OMAP3430_LASTLOGICSTATEENTERED_MASK);
> -}
> -
> -static int omap3_get_mem_bank_lastmemst_mask(u8 bank)
> -{
> -	switch (bank) {
> -	case 0:
> -		return OMAP3430_LASTMEM1STATEENTERED_MASK;
> -	case 1:
> -		return OMAP3430_LASTMEM2STATEENTERED_MASK;
> -	case 2:
> -		return OMAP3430_LASTSHAREDL2CACHEFLATSTATEENTERED_MASK;
> -	case 3:
> -		return OMAP3430_LASTL2FLATMEMSTATEENTERED_MASK;
> -	default:
> -		WARN_ON(1); /* should never happen */
> -		return -EEXIST;
> -	}
> -	return 0;
> -}
> -
> -static int omap3_pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
> -{
> -	u32 m;
> -
> -	m = omap3_get_mem_bank_lastmemst_mask(bank);
> -
> -	return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
> -				OMAP3430_PM_PREPWSTST, m);
> -}
> -
> -static int omap3_pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
> -{
> -	omap2_prm_write_mod_reg(0, pwrdm->prcm_offs, OMAP3430_PM_PREPWSTST);
> -	return 0;
> -}
> -
> -static int omap3_pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm)
> -{
> -	return omap2_prm_rmw_mod_reg_bits(0,
> -					  1 << OMAP3430ES2_SAVEANDRESTORE_SHIFT,
> -					  pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL);
> -}
> -
> -static int omap3_pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm)
> -{
> -	return omap2_prm_rmw_mod_reg_bits(1 << OMAP3430ES2_SAVEANDRESTORE_SHIFT,
> -					  0, pwrdm->prcm_offs,
> -					  OMAP2_PM_PWSTCTRL);
> -}
> -
> -struct pwrdm_ops omap2_pwrdm_operations = {
> -	.pwrdm_set_next_pwrst	= omap2_pwrdm_set_next_pwrst,
> -	.pwrdm_read_next_pwrst	= omap2_pwrdm_read_next_pwrst,
> -	.pwrdm_read_pwrst	= omap2_pwrdm_read_pwrst,
> -	.pwrdm_set_logic_retst	= omap2_pwrdm_set_logic_retst,
> -	.pwrdm_set_mem_onst	= omap2_pwrdm_set_mem_onst,
> -	.pwrdm_set_mem_retst	= omap2_pwrdm_set_mem_retst,
> -	.pwrdm_read_mem_pwrst	= omap2_pwrdm_read_mem_pwrst,
> -	.pwrdm_read_mem_retst	= omap2_pwrdm_read_mem_retst,
> -	.pwrdm_wait_transition	= omap2_pwrdm_wait_transition,
> -};
> -
> -struct pwrdm_ops omap3_pwrdm_operations = {
> -	.pwrdm_set_next_pwrst	= omap2_pwrdm_set_next_pwrst,
> -	.pwrdm_read_next_pwrst	= omap2_pwrdm_read_next_pwrst,
> -	.pwrdm_read_pwrst	= omap2_pwrdm_read_pwrst,
> -	.pwrdm_read_prev_pwrst	= omap3_pwrdm_read_prev_pwrst,
> -	.pwrdm_set_logic_retst	= omap2_pwrdm_set_logic_retst,
> -	.pwrdm_read_logic_pwrst	= omap3_pwrdm_read_logic_pwrst,
> -	.pwrdm_read_logic_retst	= omap3_pwrdm_read_logic_retst,
> -	.pwrdm_read_prev_logic_pwrst	= omap3_pwrdm_read_prev_logic_pwrst,
> -	.pwrdm_set_mem_onst	= omap2_pwrdm_set_mem_onst,
> -	.pwrdm_set_mem_retst	= omap2_pwrdm_set_mem_retst,
> -	.pwrdm_read_mem_pwrst	= omap2_pwrdm_read_mem_pwrst,
> -	.pwrdm_read_mem_retst	= omap2_pwrdm_read_mem_retst,
> -	.pwrdm_read_prev_mem_pwrst	= omap3_pwrdm_read_prev_mem_pwrst,
> -	.pwrdm_clear_all_prev_pwrst	= omap3_pwrdm_clear_all_prev_pwrst,
> -	.pwrdm_enable_hdwr_sar	= omap3_pwrdm_enable_hdwr_sar,
> -	.pwrdm_disable_hdwr_sar	= omap3_pwrdm_disable_hdwr_sar,
> -	.pwrdm_wait_transition	= omap2_pwrdm_wait_transition,
> -};
> diff --git a/arch/arm/mach-omap2/powerdomain33xx.c b/arch/arm/mach-omap2/powerdomain33xx.c
> deleted file mode 100644
> index 67c5663..0000000
> --- a/arch/arm/mach-omap2/powerdomain33xx.c
> +++ /dev/null
> @@ -1,229 +0,0 @@
> -/*
> - * AM33XX Powerdomain control
> - *
> - * Copyright (C) 2011-2012 Texas Instruments Incorporated - http://www.ti.com/
> - *
> - * Derived from mach-omap2/powerdomain44xx.c written by Rajendra Nayak
> - * <rnayak@ti.com>
> - *
> - * This program is free software; you can redistribute it and/or
> - * modify it under the terms of the GNU General Public License as
> - * published by the Free Software Foundation version 2.
> - *
> - * This program is distributed "as is" WITHOUT ANY WARRANTY of any
> - * kind, whether express or implied; without even the implied warranty
> - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> - * GNU General Public License for more details.
> - */
> -
> -#include <linux/io.h>
> -#include <linux/errno.h>
> -#include <linux/delay.h>
> -
> -#include <plat/prcm.h>
> -
> -#include "powerdomain.h"
> -#include "prm33xx.h"
> -#include "prm-regbits-33xx.h"
> -
> -
> -static int am33xx_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
> -{
> -	am33xx_prm_rmw_reg_bits(OMAP_POWERSTATE_MASK,
> -				(pwrst << OMAP_POWERSTATE_SHIFT),
> -				pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
> -	return 0;
> -}
> -
> -static int am33xx_pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
> -{
> -	u32 v;
> -
> -	v = am33xx_prm_read_reg(pwrdm->prcm_offs,  pwrdm->pwrstctrl_offs);
> -	v &= OMAP_POWERSTATE_MASK;
> -	v >>= OMAP_POWERSTATE_SHIFT;
> -
> -	return v;
> -}
> -
> -static int am33xx_pwrdm_read_pwrst(struct powerdomain *pwrdm)
> -{
> -	u32 v;
> -
> -	v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs);
> -	v &= OMAP_POWERSTATEST_MASK;
> -	v >>= OMAP_POWERSTATEST_SHIFT;
> -
> -	return v;
> -}
> -
> -static int am33xx_pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
> -{
> -	u32 v;
> -
> -	v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs);
> -	v &= AM33XX_LASTPOWERSTATEENTERED_MASK;
> -	v >>= AM33XX_LASTPOWERSTATEENTERED_SHIFT;
> -
> -	return v;
> -}
> -
> -static int am33xx_pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm)
> -{
> -	am33xx_prm_rmw_reg_bits(AM33XX_LOWPOWERSTATECHANGE_MASK,
> -				(1 << AM33XX_LOWPOWERSTATECHANGE_SHIFT),
> -				pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
> -	return 0;
> -}
> -
> -static int am33xx_pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
> -{
> -	am33xx_prm_rmw_reg_bits(AM33XX_LASTPOWERSTATEENTERED_MASK,
> -				AM33XX_LASTPOWERSTATEENTERED_MASK,
> -				pwrdm->prcm_offs, pwrdm->pwrstst_offs);
> -	return 0;
> -}
> -
> -static int am33xx_pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
> -{
> -	u32 m;
> -
> -	m = pwrdm->logicretstate_mask;
> -	if (!m)
> -		return -EINVAL;
> -
> -	am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)),
> -				pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
> -
> -	return 0;
> -}
> -
> -static int am33xx_pwrdm_read_logic_pwrst(struct powerdomain *pwrdm)
> -{
> -	u32 v;
> -
> -	v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs);
> -	v &= AM33XX_LOGICSTATEST_MASK;
> -	v >>= AM33XX_LOGICSTATEST_SHIFT;
> -
> -	return v;
> -}
> -
> -static int am33xx_pwrdm_read_logic_retst(struct powerdomain *pwrdm)
> -{
> -	u32 v, m;
> -
> -	m = pwrdm->logicretstate_mask;
> -	if (!m)
> -		return -EINVAL;
> -
> -	v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
> -	v &= m;
> -	v >>= __ffs(m);
> -
> -	return v;
> -}
> -
> -static int am33xx_pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank,
> -		u8 pwrst)
> -{
> -	u32 m;
> -
> -	m = pwrdm->mem_on_mask[bank];
> -	if (!m)
> -		return -EINVAL;
> -
> -	am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)),
> -				pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
> -
> -	return 0;
> -}
> -
> -static int am33xx_pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank,
> -					u8 pwrst)
> -{
> -	u32 m;
> -
> -	m = pwrdm->mem_ret_mask[bank];
> -	if (!m)
> -		return -EINVAL;
> -
> -	am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)),
> -				pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
> -
> -	return 0;
> -}
> -
> -static int am33xx_pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
> -{
> -	u32 m, v;
> -
> -	m = pwrdm->mem_pwrst_mask[bank];
> -	if (!m)
> -		return -EINVAL;
> -
> -	v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs);
> -	v &= m;
> -	v >>= __ffs(m);
> -
> -	return v;
> -}
> -
> -static int am33xx_pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank)
> -{
> -	u32 m, v;
> -
> -	m = pwrdm->mem_retst_mask[bank];
> -	if (!m)
> -		return -EINVAL;
> -
> -	v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
> -	v &= m;
> -	v >>= __ffs(m);
> -
> -	return v;
> -}
> -
> -static int am33xx_pwrdm_wait_transition(struct powerdomain *pwrdm)
> -{
> -	u32 c = 0;
> -
> -	/*
> -	 * REVISIT: pwrdm_wait_transition() may be better implemented
> -	 * via a callback and a periodic timer check -- how long do we expect
> -	 * powerdomain transitions to take?
> -	 */
> -
> -	/* XXX Is this udelay() value meaningful? */
> -	while ((am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs)
> -			& OMAP_INTRANSITION_MASK) &&
> -			(c++ < PWRDM_TRANSITION_BAILOUT))
> -		udelay(1);
> -
> -	if (c > PWRDM_TRANSITION_BAILOUT) {
> -		pr_err("powerdomain: %s: waited too long to complete transition\n",
> -		       pwrdm->name);
> -		return -EAGAIN;
> -	}
> -
> -	pr_debug("powerdomain: completed transition in %d loops\n", c);
> -
> -	return 0;
> -}
> -
> -struct pwrdm_ops am33xx_pwrdm_operations = {
> -	.pwrdm_set_next_pwrst		= am33xx_pwrdm_set_next_pwrst,
> -	.pwrdm_read_next_pwrst		= am33xx_pwrdm_read_next_pwrst,
> -	.pwrdm_read_pwrst		= am33xx_pwrdm_read_pwrst,
> -	.pwrdm_read_prev_pwrst		= am33xx_pwrdm_read_prev_pwrst,
> -	.pwrdm_set_logic_retst		= am33xx_pwrdm_set_logic_retst,
> -	.pwrdm_read_logic_pwrst		= am33xx_pwrdm_read_logic_pwrst,
> -	.pwrdm_read_logic_retst		= am33xx_pwrdm_read_logic_retst,
> -	.pwrdm_clear_all_prev_pwrst	= am33xx_pwrdm_clear_all_prev_pwrst,
> -	.pwrdm_set_lowpwrstchange	= am33xx_pwrdm_set_lowpwrstchange,
> -	.pwrdm_read_mem_pwrst		= am33xx_pwrdm_read_mem_pwrst,
> -	.pwrdm_read_mem_retst		= am33xx_pwrdm_read_mem_retst,
> -	.pwrdm_set_mem_onst		= am33xx_pwrdm_set_mem_onst,
> -	.pwrdm_set_mem_retst		= am33xx_pwrdm_set_mem_retst,
> -	.pwrdm_wait_transition		= am33xx_pwrdm_wait_transition,
> -};
> diff --git a/arch/arm/mach-omap2/powerdomain44xx.c b/arch/arm/mach-omap2/powerdomain44xx.c
> deleted file mode 100644
> index aceb4f4..0000000
> --- a/arch/arm/mach-omap2/powerdomain44xx.c
> +++ /dev/null
> @@ -1,285 +0,0 @@
> -/*
> - * OMAP4 powerdomain control
> - *
> - * Copyright (C) 2009-2010, 2012 Texas Instruments, Inc.
> - * Copyright (C) 2007-2009 Nokia Corporation
> - *
> - * Derived from mach-omap2/powerdomain.c written by Paul Walmsley
> - * Rajendra Nayak <rnayak@ti.com>
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License version 2 as
> - * published by the Free Software Foundation.
> - */
> -
> -#include <linux/io.h>
> -#include <linux/errno.h>
> -#include <linux/delay.h>
> -#include <linux/bug.h>
> -
> -#include "powerdomain.h"
> -#include <plat/prcm.h>
> -#include "prm2xxx_3xxx.h"
> -#include "prm44xx.h"
> -#include "prminst44xx.h"
> -#include "prm-regbits-44xx.h"
> -
> -static int omap4_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
> -{
> -	omap4_prminst_rmw_inst_reg_bits(OMAP_POWERSTATE_MASK,
> -					(pwrst << OMAP_POWERSTATE_SHIFT),
> -					pwrdm->prcm_partition,
> -					pwrdm->prcm_offs, OMAP4_PM_PWSTCTRL);
> -	return 0;
> -}
> -
> -static int omap4_pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
> -{
> -	u32 v;
> -
> -	v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs,
> -					OMAP4_PM_PWSTCTRL);
> -	v &= OMAP_POWERSTATE_MASK;
> -	v >>= OMAP_POWERSTATE_SHIFT;
> -
> -	return v;
> -}
> -
> -static int omap4_pwrdm_read_pwrst(struct powerdomain *pwrdm)
> -{
> -	u32 v;
> -
> -	v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs,
> -					OMAP4_PM_PWSTST);
> -	v &= OMAP_POWERSTATEST_MASK;
> -	v >>= OMAP_POWERSTATEST_SHIFT;
> -
> -	return v;
> -}
> -
> -static int omap4_pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
> -{
> -	u32 v;
> -
> -	v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs,
> -					OMAP4_PM_PWSTST);
> -	v &= OMAP4430_LASTPOWERSTATEENTERED_MASK;
> -	v >>= OMAP4430_LASTPOWERSTATEENTERED_SHIFT;
> -
> -	return v;
> -}
> -
> -static int omap4_pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm)
> -{
> -	omap4_prminst_rmw_inst_reg_bits(OMAP4430_LOWPOWERSTATECHANGE_MASK,
> -					(1 << OMAP4430_LOWPOWERSTATECHANGE_SHIFT),
> -					pwrdm->prcm_partition,
> -					pwrdm->prcm_offs, OMAP4_PM_PWSTCTRL);
> -	return 0;
> -}
> -
> -static int omap4_pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
> -{
> -	omap4_prminst_rmw_inst_reg_bits(OMAP4430_LASTPOWERSTATEENTERED_MASK,
> -					OMAP4430_LASTPOWERSTATEENTERED_MASK,
> -					pwrdm->prcm_partition,
> -					pwrdm->prcm_offs, OMAP4_PM_PWSTST);
> -	return 0;
> -}
> -
> -static int omap4_pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
> -{
> -	u32 v;
> -
> -	v = pwrst << __ffs(OMAP4430_LOGICRETSTATE_MASK);
> -	omap4_prminst_rmw_inst_reg_bits(OMAP4430_LOGICRETSTATE_MASK, v,
> -					pwrdm->prcm_partition, pwrdm->prcm_offs,
> -					OMAP4_PM_PWSTCTRL);
> -
> -	return 0;
> -}
> -
> -static int omap4_pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank,
> -				    u8 pwrst)
> -{
> -	u32 m;
> -
> -	m = omap2_pwrdm_get_mem_bank_onstate_mask(bank);
> -
> -	omap4_prminst_rmw_inst_reg_bits(m, (pwrst << __ffs(m)),
> -					pwrdm->prcm_partition, pwrdm->prcm_offs,
> -					OMAP4_PM_PWSTCTRL);
> -
> -	return 0;
> -}
> -
> -static int omap4_pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank,
> -				     u8 pwrst)
> -{
> -	u32 m;
> -
> -	m = omap2_pwrdm_get_mem_bank_retst_mask(bank);
> -
> -	omap4_prminst_rmw_inst_reg_bits(m, (pwrst << __ffs(m)),
> -					pwrdm->prcm_partition, pwrdm->prcm_offs,
> -					OMAP4_PM_PWSTCTRL);
> -
> -	return 0;
> -}
> -
> -static int omap4_pwrdm_read_logic_pwrst(struct powerdomain *pwrdm)
> -{
> -	u32 v;
> -
> -	v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs,
> -					OMAP4_PM_PWSTST);
> -	v &= OMAP4430_LOGICSTATEST_MASK;
> -	v >>= OMAP4430_LOGICSTATEST_SHIFT;
> -
> -	return v;
> -}
> -
> -static int omap4_pwrdm_read_logic_retst(struct powerdomain *pwrdm)
> -{
> -	u32 v;
> -
> -	v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs,
> -					OMAP4_PM_PWSTCTRL);
> -	v &= OMAP4430_LOGICRETSTATE_MASK;
> -	v >>= OMAP4430_LOGICRETSTATE_SHIFT;
> -
> -	return v;
> -}
> -
> -/**
> - * omap4_pwrdm_read_prev_logic_pwrst - read the previous logic powerstate
> - * @pwrdm: struct powerdomain * to read the state for
> - *
> - * Reads the previous logic powerstate for a powerdomain. This
> - * function must determine the previous logic powerstate by first
> - * checking the previous powerstate for the domain. If that was OFF,
> - * then logic has been lost. If previous state was RETENTION, the
> - * function reads the setting for the next retention logic state to
> - * see the actual value.  In every other case, the logic is
> - * retained. Returns either PWRDM_POWER_OFF or PWRDM_POWER_RET
> - * depending whether the logic was retained or not.
> - */
> -static int omap4_pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm)
> -{
> -	int state;
> -
> -	state = omap4_pwrdm_read_prev_pwrst(pwrdm);
> -
> -	if (state == PWRDM_POWER_OFF)
> -		return PWRDM_POWER_OFF;
> -
> -	if (state != PWRDM_POWER_RET)
> -		return PWRDM_POWER_RET;
> -
> -	return omap4_pwrdm_read_logic_retst(pwrdm);
> -}
> -
> -static int omap4_pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
> -{
> -	u32 m, v;
> -
> -	m = omap2_pwrdm_get_mem_bank_stst_mask(bank);
> -
> -	v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs,
> -					OMAP4_PM_PWSTST);
> -	v &= m;
> -	v >>= __ffs(m);
> -
> -	return v;
> -}
> -
> -static int omap4_pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank)
> -{
> -	u32 m, v;
> -
> -	m = omap2_pwrdm_get_mem_bank_retst_mask(bank);
> -
> -	v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs,
> -					OMAP4_PM_PWSTCTRL);
> -	v &= m;
> -	v >>= __ffs(m);
> -
> -	return v;
> -}
> -
> -/**
> - * omap4_pwrdm_read_prev_mem_pwrst - reads the previous memory powerstate
> - * @pwrdm: struct powerdomain * to read mem powerstate for
> - * @bank: memory bank index
> - *
> - * Reads the previous memory powerstate for a powerdomain. This
> - * function must determine the previous memory powerstate by first
> - * checking the previous powerstate for the domain. If that was OFF,
> - * then logic has been lost. If previous state was RETENTION, the
> - * function reads the setting for the next memory retention state to
> - * see the actual value.  In every other case, the logic is
> - * retained. Returns either PWRDM_POWER_OFF or PWRDM_POWER_RET
> - * depending whether logic was retained or not.
> - */
> -static int omap4_pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
> -{
> -	int state;
> -
> -	state = omap4_pwrdm_read_prev_pwrst(pwrdm);
> -
> -	if (state == PWRDM_POWER_OFF)
> -		return PWRDM_POWER_OFF;
> -
> -	if (state != PWRDM_POWER_RET)
> -		return PWRDM_POWER_RET;
> -
> -	return omap4_pwrdm_read_mem_retst(pwrdm, bank);
> -}
> -
> -static int omap4_pwrdm_wait_transition(struct powerdomain *pwrdm)
> -{
> -	u32 c = 0;
> -
> -	/*
> -	 * REVISIT: pwrdm_wait_transition() may be better implemented
> -	 * via a callback and a periodic timer check -- how long do we expect
> -	 * powerdomain transitions to take?
> -	 */
> -
> -	/* XXX Is this udelay() value meaningful? */
> -	while ((omap4_prminst_read_inst_reg(pwrdm->prcm_partition,
> -					    pwrdm->prcm_offs,
> -					    OMAP4_PM_PWSTST) &
> -		OMAP_INTRANSITION_MASK) &&
> -	       (c++ < PWRDM_TRANSITION_BAILOUT))
> -		udelay(1);
> -
> -	if (c > PWRDM_TRANSITION_BAILOUT) {
> -		pr_err("powerdomain: %s: waited too long to complete transition\n",
> -		       pwrdm->name);
> -		return -EAGAIN;
> -	}
> -
> -	pr_debug("powerdomain: completed transition in %d loops\n", c);
> -
> -	return 0;
> -}
> -
> -struct pwrdm_ops omap4_pwrdm_operations = {
> -	.pwrdm_set_next_pwrst	= omap4_pwrdm_set_next_pwrst,
> -	.pwrdm_read_next_pwrst	= omap4_pwrdm_read_next_pwrst,
> -	.pwrdm_read_pwrst	= omap4_pwrdm_read_pwrst,
> -	.pwrdm_read_prev_pwrst	= omap4_pwrdm_read_prev_pwrst,
> -	.pwrdm_set_lowpwrstchange	= omap4_pwrdm_set_lowpwrstchange,
> -	.pwrdm_clear_all_prev_pwrst	= omap4_pwrdm_clear_all_prev_pwrst,
> -	.pwrdm_set_logic_retst	= omap4_pwrdm_set_logic_retst,
> -	.pwrdm_read_logic_pwrst	= omap4_pwrdm_read_logic_pwrst,
> -	.pwrdm_read_prev_logic_pwrst	= omap4_pwrdm_read_prev_logic_pwrst,
> -	.pwrdm_read_logic_retst	= omap4_pwrdm_read_logic_retst,
> -	.pwrdm_read_mem_pwrst	= omap4_pwrdm_read_mem_pwrst,
> -	.pwrdm_read_mem_retst	= omap4_pwrdm_read_mem_retst,
> -	.pwrdm_read_prev_mem_pwrst	= omap4_pwrdm_read_prev_mem_pwrst,
> -	.pwrdm_set_mem_onst	= omap4_pwrdm_set_mem_onst,
> -	.pwrdm_set_mem_retst	= omap4_pwrdm_set_mem_retst,
> -	.pwrdm_wait_transition	= omap4_pwrdm_wait_transition,
> -};
> diff --git a/arch/arm/mach-omap2/prm2xxx.c b/arch/arm/mach-omap2/prm2xxx.c
> new file mode 100644
> index 0000000..14940c4
> --- /dev/null
> +++ b/arch/arm/mach-omap2/prm2xxx.c
> @@ -0,0 +1,40 @@
> +/*
> + * OMAP2xxx PRM module functions
> + *
> + * Copyright (C) 2010-2012 Texas Instruments, Inc.
> + * Copyright (C) 2010 Nokia Corporation
> + * Beno?t Cousson
> + * Paul Walmsley
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/irq.h>
> +
> +#include "common.h"
> +#include <plat/cpu.h>
> +#include <plat/prcm.h>
> +
> +#include "vp.h"
> +#include "powerdomain.h"
> +#include "prm2xxx.h"
> +#include "cm2xxx_3xxx.h"
> +#include "prm-regbits-24xx.h"
> +
> +struct pwrdm_ops omap2_pwrdm_operations = {
> +	.pwrdm_set_next_pwrst	= omap2_pwrdm_set_next_pwrst,
> +	.pwrdm_read_next_pwrst	= omap2_pwrdm_read_next_pwrst,
> +	.pwrdm_read_pwrst	= omap2_pwrdm_read_pwrst,
> +	.pwrdm_set_logic_retst	= omap2_pwrdm_set_logic_retst,
> +	.pwrdm_set_mem_onst	= omap2_pwrdm_set_mem_onst,
> +	.pwrdm_set_mem_retst	= omap2_pwrdm_set_mem_retst,
> +	.pwrdm_read_mem_pwrst	= omap2_pwrdm_read_mem_pwrst,
> +	.pwrdm_read_mem_retst	= omap2_pwrdm_read_mem_retst,
> +	.pwrdm_wait_transition	= omap2_pwrdm_wait_transition,
> +};
> diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c
> index 0d6cc54..bdddf5c 100644
> --- a/arch/arm/mach-omap2/prm2xxx_3xxx.c
> +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c
> @@ -17,7 +17,7 @@
>   #include <linux/io.h>
>
>   #include "common.h"
> -
> +#include "powerdomain.h"
>   #include "prm2xxx_3xxx.h"
>   #include "prm-regbits-24xx.h"
>
> @@ -98,3 +98,113 @@ int omap2_prm_deassert_hardreset(s16 prm_mod, u8 rst_shift, u8 st_shift)
>   	return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0;
>   }
>
> +
> +/* Powerdomain low-level functions */
> +
> +/* Common functions across OMAP2 and OMAP3 */
> +int omap2_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
> +{
> +	omap2_prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK,
> +				   (pwrst << OMAP_POWERSTATE_SHIFT),
> +				   pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL);
> +	return 0;
> +}
> +
> +int omap2_pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
> +{
> +	return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
> +					     OMAP2_PM_PWSTCTRL,
> +					     OMAP_POWERSTATE_MASK);
> +}
> +
> +int omap2_pwrdm_read_pwrst(struct powerdomain *pwrdm)
> +{
> +	return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
> +					     OMAP2_PM_PWSTST,
> +					     OMAP_POWERSTATEST_MASK);
> +}
> +
> +int omap2_pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank,
> +								u8 pwrst)
> +{
> +	u32 m;
> +
> +	m = omap2_pwrdm_get_mem_bank_onstate_mask(bank);
> +
> +	omap2_prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)), pwrdm->prcm_offs,
> +				   OMAP2_PM_PWSTCTRL);
> +
> +	return 0;
> +}
> +
> +int omap2_pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank,
> +								u8 pwrst)
> +{
> +	u32 m;
> +
> +	m = omap2_pwrdm_get_mem_bank_retst_mask(bank);
> +
> +	omap2_prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)), pwrdm->prcm_offs,
> +				   OMAP2_PM_PWSTCTRL);
> +
> +	return 0;
> +}
> +
> +int omap2_pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
> +{
> +	u32 m;
> +
> +	m = omap2_pwrdm_get_mem_bank_stst_mask(bank);
> +
> +	return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, OMAP2_PM_PWSTST,
> +					     m);
> +}
> +
> +int omap2_pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank)
> +{
> +	u32 m;
> +
> +	m = omap2_pwrdm_get_mem_bank_retst_mask(bank);
> +
> +	return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
> +					     OMAP2_PM_PWSTCTRL, m);
> +}
> +
> +int omap2_pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
> +{
> +	u32 v;
> +
> +	v = pwrst << __ffs(OMAP_LOGICRETSTATE_MASK);
> +	omap2_prm_rmw_mod_reg_bits(OMAP_LOGICRETSTATE_MASK, v, pwrdm->prcm_offs,
> +				   OMAP2_PM_PWSTCTRL);
> +
> +	return 0;
> +}
> +
> +int omap2_pwrdm_wait_transition(struct powerdomain *pwrdm)
> +{
> +	u32 c = 0;
> +
> +	/*
> +	 * REVISIT: pwrdm_wait_transition() may be better implemented
> +	 * via a callback and a periodic timer check -- how long do we expect
> +	 * powerdomain transitions to take?
> +	 */
> +
> +	/* XXX Is this udelay() value meaningful? */
> +	while ((omap2_prm_read_mod_reg(pwrdm->prcm_offs, OMAP2_PM_PWSTST) &
> +		OMAP_INTRANSITION_MASK) &&
> +		(c++ < PWRDM_TRANSITION_BAILOUT))
> +			udelay(1);
> +
> +	if (c > PWRDM_TRANSITION_BAILOUT) {
> +		pr_err("powerdomain: %s: waited too long to complete transition\n",
> +		       pwrdm->name);
> +		return -EAGAIN;
> +	}
> +
> +	pr_debug("powerdomain: completed transition in %d loops\n", c);
> +
> +	return 0;
> +}
> +
> diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.h b/arch/arm/mach-omap2/prm2xxx_3xxx.h
> index 8d09a1a..706b026 100644
> --- a/arch/arm/mach-omap2/prm2xxx_3xxx.h
> +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.h
> @@ -50,6 +50,7 @@
>   #ifndef __ASSEMBLER__
>
>   #include <linux/io.h>
> +#include "powerdomain.h"
>
>   /* Power/reset management domain register get/set */
>   static inline u32 omap2_prm_read_mod_reg(s16 module, u16 idx)
> @@ -103,6 +104,18 @@ extern int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift);
>   extern int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift);
>   extern int omap2_prm_deassert_hardreset(s16 prm_mod, u8 rst_shift, u8 st_shift);
>
> +extern int omap2_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst);
> +extern int omap2_pwrdm_read_next_pwrst(struct powerdomain *pwrdm);
> +extern int omap2_pwrdm_read_pwrst(struct powerdomain *pwrdm);
> +extern int omap2_pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank,
> +				    u8 pwrst);
> +extern int omap2_pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank,
> +				     u8 pwrst);
> +extern int omap2_pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank);
> +extern int omap2_pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank);
> +extern int omap2_pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst);
> +extern int omap2_pwrdm_wait_transition(struct powerdomain *pwrdm);
> +
>   #endif /* __ASSEMBLER */
>
>   /*
> diff --git a/arch/arm/mach-omap2/prm33xx.c b/arch/arm/mach-omap2/prm33xx.c
> index e7dbb6c..3417dd3 100644
> --- a/arch/arm/mach-omap2/prm33xx.c
> +++ b/arch/arm/mach-omap2/prm33xx.c
> @@ -22,6 +22,7 @@
>   #include <plat/common.h>
>
>   #include "common.h"
> +#include "powerdomain.h"
>   #include "prm33xx.h"
>   #include "prm-regbits-33xx.h"
>
> @@ -133,3 +134,204 @@ int am33xx_prm_deassert_hardreset(u8 shift, s16 inst,
>
>   	return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0;
>   }
> +
> +static int am33xx_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
> +{
> +	am33xx_prm_rmw_reg_bits(OMAP_POWERSTATE_MASK,
> +				(pwrst << OMAP_POWERSTATE_SHIFT),
> +				pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
> +	return 0;
> +}
> +
> +static int am33xx_pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
> +{
> +	u32 v;
> +
> +	v = am33xx_prm_read_reg(pwrdm->prcm_offs,  pwrdm->pwrstctrl_offs);
> +	v &= OMAP_POWERSTATE_MASK;
> +	v >>= OMAP_POWERSTATE_SHIFT;
> +
> +	return v;
> +}
> +
> +static int am33xx_pwrdm_read_pwrst(struct powerdomain *pwrdm)
> +{
> +	u32 v;
> +
> +	v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs);
> +	v &= OMAP_POWERSTATEST_MASK;
> +	v >>= OMAP_POWERSTATEST_SHIFT;
> +
> +	return v;
> +}
> +
> +static int am33xx_pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
> +{
> +	u32 v;
> +
> +	v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs);
> +	v &= AM33XX_LASTPOWERSTATEENTERED_MASK;
> +	v >>= AM33XX_LASTPOWERSTATEENTERED_SHIFT;
> +
> +	return v;
> +}
> +
> +static int am33xx_pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm)
> +{
> +	am33xx_prm_rmw_reg_bits(AM33XX_LOWPOWERSTATECHANGE_MASK,
> +				(1 << AM33XX_LOWPOWERSTATECHANGE_SHIFT),
> +				pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
> +	return 0;
> +}
> +
> +static int am33xx_pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
> +{
> +	am33xx_prm_rmw_reg_bits(AM33XX_LASTPOWERSTATEENTERED_MASK,
> +				AM33XX_LASTPOWERSTATEENTERED_MASK,
> +				pwrdm->prcm_offs, pwrdm->pwrstst_offs);
> +	return 0;
> +}
> +
> +static int am33xx_pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
> +{
> +	u32 m;
> +
> +	m = pwrdm->logicretstate_mask;
> +	if (!m)
> +		return -EINVAL;
> +
> +	am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)),
> +				pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
> +
> +	return 0;
> +}
> +
> +static int am33xx_pwrdm_read_logic_pwrst(struct powerdomain *pwrdm)
> +{
> +	u32 v;
> +
> +	v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs);
> +	v &= AM33XX_LOGICSTATEST_MASK;
> +	v >>= AM33XX_LOGICSTATEST_SHIFT;
> +
> +	return v;
> +}
> +
> +static int am33xx_pwrdm_read_logic_retst(struct powerdomain *pwrdm)
> +{
> +	u32 v, m;
> +
> +	m = pwrdm->logicretstate_mask;
> +	if (!m)
> +		return -EINVAL;
> +
> +	v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
> +	v &= m;
> +	v >>= __ffs(m);
> +
> +	return v;
> +}
> +
> +static int am33xx_pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank,
> +		u8 pwrst)
> +{
> +	u32 m;
> +
> +	m = pwrdm->mem_on_mask[bank];
> +	if (!m)
> +		return -EINVAL;
> +
> +	am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)),
> +				pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
> +
> +	return 0;
> +}
> +
> +static int am33xx_pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank,
> +					u8 pwrst)
> +{
> +	u32 m;
> +
> +	m = pwrdm->mem_ret_mask[bank];
> +	if (!m)
> +		return -EINVAL;
> +
> +	am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)),
> +				pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
> +
> +	return 0;
> +}
> +
> +static int am33xx_pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
> +{
> +	u32 m, v;
> +
> +	m = pwrdm->mem_pwrst_mask[bank];
> +	if (!m)
> +		return -EINVAL;
> +
> +	v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs);
> +	v &= m;
> +	v >>= __ffs(m);
> +
> +	return v;
> +}
> +
> +static int am33xx_pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank)
> +{
> +	u32 m, v;
> +
> +	m = pwrdm->mem_retst_mask[bank];
> +	if (!m)
> +		return -EINVAL;
> +
> +	v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
> +	v &= m;
> +	v >>= __ffs(m);
> +
> +	return v;
> +}
> +
> +static int am33xx_pwrdm_wait_transition(struct powerdomain *pwrdm)
> +{
> +	u32 c = 0;
> +
> +	/*
> +	 * REVISIT: pwrdm_wait_transition() may be better implemented
> +	 * via a callback and a periodic timer check -- how long do we expect
> +	 * powerdomain transitions to take?
> +	 */
> +
> +	/* XXX Is this udelay() value meaningful? */
> +	while ((am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs)
> +			& OMAP_INTRANSITION_MASK) &&
> +			(c++ < PWRDM_TRANSITION_BAILOUT))
> +		udelay(1);
> +
> +	if (c > PWRDM_TRANSITION_BAILOUT) {
> +		pr_err("powerdomain: %s: waited too long to complete transition\n",
> +		       pwrdm->name);
> +		return -EAGAIN;
> +	}
> +
> +	pr_debug("powerdomain: completed transition in %d loops\n", c);
> +
> +	return 0;
> +}
> +
> +struct pwrdm_ops am33xx_pwrdm_operations = {
> +	.pwrdm_set_next_pwrst		= am33xx_pwrdm_set_next_pwrst,
> +	.pwrdm_read_next_pwrst		= am33xx_pwrdm_read_next_pwrst,
> +	.pwrdm_read_pwrst		= am33xx_pwrdm_read_pwrst,
> +	.pwrdm_read_prev_pwrst		= am33xx_pwrdm_read_prev_pwrst,
> +	.pwrdm_set_logic_retst		= am33xx_pwrdm_set_logic_retst,
> +	.pwrdm_read_logic_pwrst		= am33xx_pwrdm_read_logic_pwrst,
> +	.pwrdm_read_logic_retst		= am33xx_pwrdm_read_logic_retst,
> +	.pwrdm_clear_all_prev_pwrst	= am33xx_pwrdm_clear_all_prev_pwrst,
> +	.pwrdm_set_lowpwrstchange	= am33xx_pwrdm_set_lowpwrstchange,
> +	.pwrdm_read_mem_pwrst		= am33xx_pwrdm_read_mem_pwrst,
> +	.pwrdm_read_mem_retst		= am33xx_pwrdm_read_mem_retst,
> +	.pwrdm_set_mem_onst		= am33xx_pwrdm_set_mem_onst,
> +	.pwrdm_set_mem_retst		= am33xx_pwrdm_set_mem_retst,
> +	.pwrdm_wait_transition		= am33xx_pwrdm_wait_transition,
> +};
> diff --git a/arch/arm/mach-omap2/prm3xxx.c b/arch/arm/mach-omap2/prm3xxx.c
> index 88f7d8d..b2c5fd9 100644
> --- a/arch/arm/mach-omap2/prm3xxx.c
> +++ b/arch/arm/mach-omap2/prm3xxx.c
> @@ -22,8 +22,9 @@
>   #include <plat/prcm.h>
>
>   #include "vp.h"
> -
> +#include "powerdomain.h"
>   #include "prm3xxx.h"
> +#include "prm2xxx_3xxx.h"
>   #include "cm2xxx_3xxx.h"
>   #include "prm-regbits-34xx.h"
>
> @@ -215,6 +216,109 @@ static void __init omap3xxx_prm_enable_io_wakeup(void)
>   					   PM_WKEN);
>   }
>
> +/* Powerdomain low-level functions */
> +
> +/* Applicable only for OMAP3. Not supported on OMAP2 */
> +static int omap3_pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
> +{
> +	return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
> +					     OMAP3430_PM_PREPWSTST,
> +					     OMAP3430_LASTPOWERSTATEENTERED_MASK);
> +}
> +
> +static int omap3_pwrdm_read_logic_pwrst(struct powerdomain *pwrdm)
> +{
> +	return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
> +					     OMAP2_PM_PWSTST,
> +					     OMAP3430_LOGICSTATEST_MASK);
> +}
> +
> +static int omap3_pwrdm_read_logic_retst(struct powerdomain *pwrdm)
> +{
> +	return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
> +					     OMAP2_PM_PWSTCTRL,
> +					     OMAP3430_LOGICSTATEST_MASK);
> +}
> +
> +static int omap3_pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm)
> +{
> +	return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
> +					     OMAP3430_PM_PREPWSTST,
> +					     OMAP3430_LASTLOGICSTATEENTERED_MASK);
> +}
> +
> +static int omap3_get_mem_bank_lastmemst_mask(u8 bank)
> +{
> +	switch (bank) {
> +	case 0:
> +		return OMAP3430_LASTMEM1STATEENTERED_MASK;
> +	case 1:
> +		return OMAP3430_LASTMEM2STATEENTERED_MASK;
> +	case 2:
> +		return OMAP3430_LASTSHAREDL2CACHEFLATSTATEENTERED_MASK;
> +	case 3:
> +		return OMAP3430_LASTL2FLATMEMSTATEENTERED_MASK;
> +	default:
> +		WARN_ON(1); /* should never happen */
> +		return -EEXIST;
> +	}
> +	return 0;
> +}
> +
> +static int omap3_pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
> +{
> +	u32 m;
> +
> +	m = omap3_get_mem_bank_lastmemst_mask(bank);
> +
> +	return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
> +				OMAP3430_PM_PREPWSTST, m);
> +}
> +
> +static int omap3_pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
> +{
> +	omap2_prm_write_mod_reg(0, pwrdm->prcm_offs, OMAP3430_PM_PREPWSTST);
> +	return 0;
> +}
> +
> +static int omap3_pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm)
> +{
> +	return omap2_prm_rmw_mod_reg_bits(0,
> +					  1 << OMAP3430ES2_SAVEANDRESTORE_SHIFT,
> +					  pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL);
> +}
> +
> +static int omap3_pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm)
> +{
> +	return omap2_prm_rmw_mod_reg_bits(1 << OMAP3430ES2_SAVEANDRESTORE_SHIFT,
> +					  0, pwrdm->prcm_offs,
> +					  OMAP2_PM_PWSTCTRL);
> +}
> +
> +struct pwrdm_ops omap3_pwrdm_operations = {
> +	.pwrdm_set_next_pwrst	= omap2_pwrdm_set_next_pwrst,
> +	.pwrdm_read_next_pwrst	= omap2_pwrdm_read_next_pwrst,
> +	.pwrdm_read_pwrst	= omap2_pwrdm_read_pwrst,
> +	.pwrdm_read_prev_pwrst	= omap3_pwrdm_read_prev_pwrst,
> +	.pwrdm_set_logic_retst	= omap2_pwrdm_set_logic_retst,
> +	.pwrdm_read_logic_pwrst	= omap3_pwrdm_read_logic_pwrst,
> +	.pwrdm_read_logic_retst	= omap3_pwrdm_read_logic_retst,
> +	.pwrdm_read_prev_logic_pwrst	= omap3_pwrdm_read_prev_logic_pwrst,
> +	.pwrdm_set_mem_onst	= omap2_pwrdm_set_mem_onst,
> +	.pwrdm_set_mem_retst	= omap2_pwrdm_set_mem_retst,
> +	.pwrdm_read_mem_pwrst	= omap2_pwrdm_read_mem_pwrst,
> +	.pwrdm_read_mem_retst	= omap2_pwrdm_read_mem_retst,
> +	.pwrdm_read_prev_mem_pwrst	= omap3_pwrdm_read_prev_mem_pwrst,
> +	.pwrdm_clear_all_prev_pwrst	= omap3_pwrdm_clear_all_prev_pwrst,
> +	.pwrdm_enable_hdwr_sar	= omap3_pwrdm_enable_hdwr_sar,
> +	.pwrdm_disable_hdwr_sar	= omap3_pwrdm_disable_hdwr_sar,
> +	.pwrdm_wait_transition	= omap2_pwrdm_wait_transition,
> +};
> +
> +/*
> + *
> + */
> +
>   static int __init omap3xxx_prm_init(void)
>   {
>   	int ret;
> diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c
> index 06bb679..9231fe5 100644
> --- a/arch/arm/mach-omap2/prm44xx.c
> +++ b/arch/arm/mach-omap2/prm44xx.c
> @@ -27,6 +27,7 @@
>   #include "prm-regbits-44xx.h"
>   #include "prcm44xx.h"
>   #include "prminst44xx.h"
> +#include "powerdomain.h"
>
>   static const struct omap_prcm_irq omap4_prcm_irqs[] = {
>   	OMAP_PRCM_IRQ("wkup",   0,      0),
> @@ -291,6 +292,269 @@ static void __init omap44xx_prm_enable_io_wakeup(void)
>   				    OMAP4_PRM_IO_PMCTRL_OFFSET);
>   }
>
> +/* Powerdomain low-level functions */
> +
> +static int omap4_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
> +{
> +	omap4_prminst_rmw_inst_reg_bits(OMAP_POWERSTATE_MASK,
> +					(pwrst << OMAP_POWERSTATE_SHIFT),
> +					pwrdm->prcm_partition,
> +					pwrdm->prcm_offs, OMAP4_PM_PWSTCTRL);
> +	return 0;
> +}
> +
> +static int omap4_pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
> +{
> +	u32 v;
> +
> +	v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs,
> +					OMAP4_PM_PWSTCTRL);
> +	v &= OMAP_POWERSTATE_MASK;
> +	v >>= OMAP_POWERSTATE_SHIFT;
> +
> +	return v;
> +}
> +
> +static int omap4_pwrdm_read_pwrst(struct powerdomain *pwrdm)
> +{
> +	u32 v;
> +
> +	v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs,
> +					OMAP4_PM_PWSTST);
> +	v &= OMAP_POWERSTATEST_MASK;
> +	v >>= OMAP_POWERSTATEST_SHIFT;
> +
> +	return v;
> +}
> +
> +static int omap4_pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
> +{
> +	u32 v;
> +
> +	v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs,
> +					OMAP4_PM_PWSTST);
> +	v &= OMAP4430_LASTPOWERSTATEENTERED_MASK;
> +	v >>= OMAP4430_LASTPOWERSTATEENTERED_SHIFT;
> +
> +	return v;
> +}
> +
> +static int omap4_pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm)
> +{
> +	omap4_prminst_rmw_inst_reg_bits(OMAP4430_LOWPOWERSTATECHANGE_MASK,
> +					(1 << OMAP4430_LOWPOWERSTATECHANGE_SHIFT),
> +					pwrdm->prcm_partition,
> +					pwrdm->prcm_offs, OMAP4_PM_PWSTCTRL);
> +	return 0;
> +}
> +
> +static int omap4_pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
> +{
> +	omap4_prminst_rmw_inst_reg_bits(OMAP4430_LASTPOWERSTATEENTERED_MASK,
> +					OMAP4430_LASTPOWERSTATEENTERED_MASK,
> +					pwrdm->prcm_partition,
> +					pwrdm->prcm_offs, OMAP4_PM_PWSTST);
> +	return 0;
> +}
> +
> +static int omap4_pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
> +{
> +	u32 v;
> +
> +	v = pwrst << __ffs(OMAP4430_LOGICRETSTATE_MASK);
> +	omap4_prminst_rmw_inst_reg_bits(OMAP4430_LOGICRETSTATE_MASK, v,
> +					pwrdm->prcm_partition, pwrdm->prcm_offs,
> +					OMAP4_PM_PWSTCTRL);
> +
> +	return 0;
> +}
> +
> +static int omap4_pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank,
> +				    u8 pwrst)
> +{
> +	u32 m;
> +
> +	m = omap2_pwrdm_get_mem_bank_onstate_mask(bank);
> +
> +	omap4_prminst_rmw_inst_reg_bits(m, (pwrst << __ffs(m)),
> +					pwrdm->prcm_partition, pwrdm->prcm_offs,
> +					OMAP4_PM_PWSTCTRL);
> +
> +	return 0;
> +}
> +
> +static int omap4_pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank,
> +				     u8 pwrst)
> +{
> +	u32 m;
> +
> +	m = omap2_pwrdm_get_mem_bank_retst_mask(bank);
> +
> +	omap4_prminst_rmw_inst_reg_bits(m, (pwrst << __ffs(m)),
> +					pwrdm->prcm_partition, pwrdm->prcm_offs,
> +					OMAP4_PM_PWSTCTRL);
> +
> +	return 0;
> +}
> +
> +static int omap4_pwrdm_read_logic_pwrst(struct powerdomain *pwrdm)
> +{
> +	u32 v;
> +
> +	v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs,
> +					OMAP4_PM_PWSTST);
> +	v &= OMAP4430_LOGICSTATEST_MASK;
> +	v >>= OMAP4430_LOGICSTATEST_SHIFT;
> +
> +	return v;
> +}
> +
> +static int omap4_pwrdm_read_logic_retst(struct powerdomain *pwrdm)
> +{
> +	u32 v;
> +
> +	v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs,
> +					OMAP4_PM_PWSTCTRL);
> +	v &= OMAP4430_LOGICRETSTATE_MASK;
> +	v >>= OMAP4430_LOGICRETSTATE_SHIFT;
> +
> +	return v;
> +}
> +
> +/**
> + * omap4_pwrdm_read_prev_logic_pwrst - read the previous logic powerstate
> + * @pwrdm: struct powerdomain * to read the state for
> + *
> + * Reads the previous logic powerstate for a powerdomain. This
> + * function must determine the previous logic powerstate by first
> + * checking the previous powerstate for the domain. If that was OFF,
> + * then logic has been lost. If previous state was RETENTION, the
> + * function reads the setting for the next retention logic state to
> + * see the actual value.  In every other case, the logic is
> + * retained. Returns either PWRDM_POWER_OFF or PWRDM_POWER_RET
> + * depending whether the logic was retained or not.
> + */
> +static int omap4_pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm)
> +{
> +	int state;
> +
> +	state = omap4_pwrdm_read_prev_pwrst(pwrdm);
> +
> +	if (state == PWRDM_POWER_OFF)
> +		return PWRDM_POWER_OFF;
> +
> +	if (state != PWRDM_POWER_RET)
> +		return PWRDM_POWER_RET;
> +
> +	return omap4_pwrdm_read_logic_retst(pwrdm);
> +}
> +
> +static int omap4_pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
> +{
> +	u32 m, v;
> +
> +	m = omap2_pwrdm_get_mem_bank_stst_mask(bank);
> +
> +	v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs,
> +					OMAP4_PM_PWSTST);
> +	v &= m;
> +	v >>= __ffs(m);
> +
> +	return v;
> +}
> +
> +static int omap4_pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank)
> +{
> +	u32 m, v;
> +
> +	m = omap2_pwrdm_get_mem_bank_retst_mask(bank);
> +
> +	v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs,
> +					OMAP4_PM_PWSTCTRL);
> +	v &= m;
> +	v >>= __ffs(m);
> +
> +	return v;
> +}
> +
> +/**
> + * omap4_pwrdm_read_prev_mem_pwrst - reads the previous memory powerstate
> + * @pwrdm: struct powerdomain * to read mem powerstate for
> + * @bank: memory bank index
> + *
> + * Reads the previous memory powerstate for a powerdomain. This
> + * function must determine the previous memory powerstate by first
> + * checking the previous powerstate for the domain. If that was OFF,
> + * then logic has been lost. If previous state was RETENTION, the
> + * function reads the setting for the next memory retention state to
> + * see the actual value.  In every other case, the logic is
> + * retained. Returns either PWRDM_POWER_OFF or PWRDM_POWER_RET
> + * depending whether logic was retained or not.
> + */
> +static int omap4_pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
> +{
> +	int state;
> +
> +	state = omap4_pwrdm_read_prev_pwrst(pwrdm);
> +
> +	if (state == PWRDM_POWER_OFF)
> +		return PWRDM_POWER_OFF;
> +
> +	if (state != PWRDM_POWER_RET)
> +		return PWRDM_POWER_RET;
> +
> +	return omap4_pwrdm_read_mem_retst(pwrdm, bank);
> +}
> +
> +static int omap4_pwrdm_wait_transition(struct powerdomain *pwrdm)
> +{
> +	u32 c = 0;
> +
> +	/*
> +	 * REVISIT: pwrdm_wait_transition() may be better implemented
> +	 * via a callback and a periodic timer check -- how long do we expect
> +	 * powerdomain transitions to take?
> +	 */
> +
> +	/* XXX Is this udelay() value meaningful? */
> +	while ((omap4_prminst_read_inst_reg(pwrdm->prcm_partition,
> +					    pwrdm->prcm_offs,
> +					    OMAP4_PM_PWSTST) &
> +		OMAP_INTRANSITION_MASK) &&
> +	       (c++ < PWRDM_TRANSITION_BAILOUT))
> +		udelay(1);
> +
> +	if (c > PWRDM_TRANSITION_BAILOUT) {
> +		pr_err("powerdomain: %s: waited too long to complete transition\n",
> +		       pwrdm->name);
> +		return -EAGAIN;
> +	}
> +
> +	pr_debug("powerdomain: completed transition in %d loops\n", c);
> +
> +	return 0;
> +}
> +
> +struct pwrdm_ops omap4_pwrdm_operations = {
> +	.pwrdm_set_next_pwrst	= omap4_pwrdm_set_next_pwrst,
> +	.pwrdm_read_next_pwrst	= omap4_pwrdm_read_next_pwrst,
> +	.pwrdm_read_pwrst	= omap4_pwrdm_read_pwrst,
> +	.pwrdm_read_prev_pwrst	= omap4_pwrdm_read_prev_pwrst,
> +	.pwrdm_set_lowpwrstchange	= omap4_pwrdm_set_lowpwrstchange,
> +	.pwrdm_clear_all_prev_pwrst	= omap4_pwrdm_clear_all_prev_pwrst,
> +	.pwrdm_set_logic_retst	= omap4_pwrdm_set_logic_retst,
> +	.pwrdm_read_logic_pwrst	= omap4_pwrdm_read_logic_pwrst,
> +	.pwrdm_read_prev_logic_pwrst	= omap4_pwrdm_read_prev_logic_pwrst,
> +	.pwrdm_read_logic_retst	= omap4_pwrdm_read_logic_retst,
> +	.pwrdm_read_mem_pwrst	= omap4_pwrdm_read_mem_pwrst,
> +	.pwrdm_read_mem_retst	= omap4_pwrdm_read_mem_retst,
> +	.pwrdm_read_prev_mem_pwrst	= omap4_pwrdm_read_prev_mem_pwrst,
> +	.pwrdm_set_mem_onst	= omap4_pwrdm_set_mem_onst,
> +	.pwrdm_set_mem_retst	= omap4_pwrdm_set_mem_retst,
> +	.pwrdm_wait_transition	= omap4_pwrdm_wait_transition,
> +};
> +
> +
>   static int __init omap4xxx_prm_init(void)
>   {
>   	if (!cpu_is_omap44xx())
>
>

^ permalink raw reply

* OMAP baseline test results for v3.7-rc1
From: Paul Walmsley @ 2012-10-18  6:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <alpine.DEB.2.00.1210180517450.8674@utopia.booyaka.com>

On Thu, 18 Oct 2012, Paul Walmsley wrote:

> Here are some basic OMAP test results for Linux v3.7-rc1.
> Logs and other details at http://www.pwsan.com/omap/testlogs/test_v3.7-rc1/

A few additional observations missing from the original message.

> Failing tests: needing investigation
> ------------------------------------
> 
> Boot tests:
> 
> * 2420n800: boot hangs during UART initialization
>   - http://lkml.org/lkml/2012/9/11/454
>   - Various attempts at fixes posted; etiology known; issue still unresolved
> 
> * CM-T3517: L3 in-band error with IPSS during boot
>   - Cause unknown but see http://marc.info/?l=linux-omap&m=134833869730129&w=2
>   - Longstanding issue; does not occur on the 3517EVM
> 
> * 3517EVM & CM-T3517: boot hangs with NFS root
>   - Likely some Kconfig, board file, and PM issues with EMAC
> 
> * CM-T3517: boot hangs with MMC boot
>   - Due to missing MMC setup in board file

* 4430es2panda: clockevents problems early in boot
  - boots with dummy_timer
  - no one-shot mode so no-HZ is likely to fail

* 4460pandaes: boot fails early
  - Appears to be timer-related

> PM tests:
> 
> * 3530es3beagle, 37xxevm, 3730beaglexm: I2C fails during resume from suspend
>   - Causes MMC to become unusable since regulators are not reenabled
>   - Can be worked around by reverting the I2C driver conversion to
>     threaded IRQs:
>     - http://marc.info/?l=linux-i2c&m=135026587102887&w=2
>   - Appears to be due to an accounting problem; under discussion:
>     - http://marc.info/?l=linux-arm-kernel&m=135042360725821&w=2
> 
> * 3530es3beagle: hangs during off-mode dynamic idle test
>   - Unknown cause; not investigated
> 
> * 37xx EVM: CORE not entering dynamic off-idle
>   - Cause unknown; dynamic retention-idle seems to work; system suspend to 
>     off works
> 
> * 3730 Beagle XM: does not serial wake from off-idle suspend when console
>   UART doesn't clock gate ("debug ignore_loglevel")
>   - Not shown in the current test logs; cause unknown

* 4430es2panda: dummy_timer warning messages during resume
  - Unknown cause; not investigated


- Paul

^ permalink raw reply

* [PATCH] dma: add new DMA control commands
From: Huang Shijie @ 2012-10-18  6:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1350541111.5263.3.camel@vkoul-udesk3>

? 2012?10?18? 14:18, Vinod Koul ??:
> Why cant you do start (prepare clock etc) when you submit the descriptor
> to dmaengine. Can be done in tx_submit callback.
> Similarly remove the clock when dma transaction gets completed.
I ever thought this method too.

But it will become low efficient in the following case:

   Assuming the gpmi-nand driver has to read out 1024 pages in one 
_SINGLE_ read operation.
The gpmi-nand will submit the descriptor to dmaengine per page. So with 
your method,
the system will repeat the enable/disable dma clock 1024 time. At every 
enable/disable dma clock,
the system has to enable the clock chain and it's parents ...

But with this patch, we only need to enable/disable dma clock one time, 
just at we select the nand chip.

thanks
Huang Shijie

^ permalink raw reply

* [PATCH 2/2] ARM: unwind: enable dumping stacks for SMP && ARM_UNWIND
From: Dave Martin @ 2012-10-18  6:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAMbhsRTL=EgBcuSwsinNz5AiDV=39Z+6zaf6_s-7vZeHJ6N=8Q@mail.gmail.com>

On Tue, Oct 16, 2012 at 02:30:20PM -0700, Colin Cross wrote:
> On Tue, Oct 16, 2012 at 3:55 AM, Russell King - ARM Linux
> <linux@arm.linux.org.uk> wrote:
> > On Tue, Oct 16, 2012 at 11:12:01AM +0100, Dave Martin wrote:
> >> On Mon, Oct 15, 2012 at 07:15:31PM -0700, Colin Cross wrote:
> >> > About half the callers to unwind_frame end up limiting the number of
> >> > frames they will follow before giving up, so I wasn't sure if I should
> >> > put an arbitrary limit in unwind_frame or just make sure all callers
> >> > are bounded.  Your idea of limiting same sp frames instead of total
> >> > frames sounds better.  I can send a new patch that adds a new field to
> >> > struct stackframe (which will need to be initialized everywhere, the
> >> > struct is usually on the stack) and limits the recursion.  Any
> >> > suggestion on the recursion limit?  I would never expect to see a real
> >> > situation with more than a few, but on the other hand parsing the
> >> > frames should be pretty fast so a high number (100?) shouldn't cause
> >> > any user visible effect.
> >>
> >> Talking to some tools guys about this, it sounds like there really
> >> shouldn't be any stackless frame except for the leaf frame.  If there are
> >> stackless functions they will probably not be visible in the frame chain
> >> at all.  So it might make sense to have a pretty small limit.  Maybe it
> >> could even be 1.  Cartainly a small number.
> >>
> >> We should also add a check for whether the current and frame and previous
> >> frame appear identical and abort if that's the case, if we don't do that
> >> already.
> >
> > The case that actually worries me is not the "end up looping for ever"
> > case, but the effects of having the stack change while the unwinder is
> > reading from it - for example:
> >
> >                 /* pop R4-R15 according to mask */
> >                 load_sp = mask & (1 << (13 - 4));
> >                 while (mask) {
> >                         if (mask & 1)
> >                                 ctrl->vrs[reg] = *vsp++;
> >                         mask >>= 1;
> >                         reg++;
> >                 }
> >
> > Remember that for a running thread, the stack will be changing all the
> > time while another CPU tries to read it to do the unwind, and also
> > remember that the bottom of stack isn't really known.  All you have is
> > the snapshot of the registers when the thread was last stopped by the
> > scheduler, and that state probably isn't valid.
> 
> If the snapshot of the registers when the thread was last stopped
> includes an sp that points somewhere in two contiguous pages of low
> memory, I don't see a problem.  From the sp we can get the bounds of
> the stack (see the valid_stack_addr function I added), and we can make
> sure the unwinder never dereferences anything outside of that stack,
> so it will never fault.  We can also make sure that the sp stays
> within that stack between frames, and moves in the right direction, so
> it will never loop (except for the leaf-node sp issue, which Dave
> Martin's idea will address).
> 
> > So what you're asking is for the unwinder to produce a backtrace from
> > a kernel stack which is possibly changing beneath it from an unknown
> > current state.
> 
> I don't think the stack changing is relevant.  With my modifications,
> the unwinder can handle an invalid value at any place in the stack
> without looping or crashing, and it doesn't matter if it is invalid
> due to changing or permanent stack corruption.  The worst it will do
> is produce a partial stack trace that ends with an invalid value.  For
> example:
> 
> shell@:/ # dd if=/dev/urandom of=/dev/null bs=1000000 count=1000000 &
> [1] 2709
> 130|shell@:/ # while true; do cat /proc/2709/stack; echo ---; done
> [<c00084d4>] gic_handle_irq+0x24/0x58
> [<c000e580>] __irq_svc+0x40/0x70
> [<ffffffff>] 0xffffffff
> ---
> [<00000099>] 0x99
> [<ffffffff>] 0xffffffff
> ---
> [<c0039728>] irq_exit+0x7c/0x98
> [<c000f888>] handle_IRQ+0x50/0xac
> [<c00084d4>] gic_handle_irq+0x24/0x58
> [<00000014>] 0x14
> [<ffffffff>] 0xffffffff
> ---
> [<c087ac40>] rcu_preempt_state+0x0/0x140
> [<ffffffff>] 0xffffffff
> ---
> [<c00084d4>] gic_handle_irq+0x24/0x58
> [<c000e580>] __irq_svc+0x40/0x70
> [<ffffffff>] 0xffffffff
> ---
> [<60000013>] 0x60000013
> [<ffffffff>] 0xffffffff
> ---
> [<d79ce000>] 0xd79ce000
> [<ffffffff>] 0xffffffff
> 
> > This doesn't sound like a particularly bright thing to be doing...
> 
> As discussed previously, this already happens, has anyone ever
> reported it as a problem?  Sysrq-t dumps all stacks by calling
> dump_backtrace(), which bypasses the check for tsk == current.  And
> any caller to unwind_backtrace with preemption on can see a changing
> stack, even on UP.

I think I agree with that view: so long as we are just adding robustness
against garbage stacks I think the proposed changes are useful anyway.
A changing stack is just one kind of garbage.  We don't have to guarantee
a sensible backtrace in that case, so long as the unwinder executes
safely and doesn't loop.

Cheers
---Dave

^ permalink raw reply

* [PATCH 11/11] nand: Increase the ecc placement locations to 640
From: Brian Norris @ 2012-10-18  6:36 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <67e0aae3b23f37feb30789f5c6cb342b5684911a.1349778821.git.vipin.kumar@st.com>

On Tue, Oct 9, 2012 at 3:44 AM, Vipin Kumar <vipin.kumar@st.com> wrote:
> Few devices like H27UBG8T2CTR have a writesize/oobsize of 8KB/640B.
> This means that the maximum oobsize has gone up to 640 bytes and consequently
> the maximum ecc placement locations have also gone up to 640.

We really need to change the nand_ecclayout struct sometime. Each one
takes something like 4+4?640+4+32?8 = 2824 bytes now, and we have 4 of
them statically declared in nand_base.c. And most drivers just declare
their own anyway. (fsl_{elbc,ifc}_nand.c have 4 and 5 of them each)

I've thought about dynamically allocating and/or changing its layout
so that we can do eccpos ranges, similar to the oobfree entries. But
this gets harder, with the old ioctl(ECCGETLAYOUT) still hanging
around, a few platform uses of nand_ecclayout, and probably some other
complications.

Anyway, this comes off as basically a complaint, while in fact, I
wanted to see if anyone else agreed and/or had any suggestions. Or,
maybe somebody could convince me not to care...

Brian

^ permalink raw reply

* [PATCH 2/3] serial: mxs-auart: add the DMA support for mx28
From: Huang Shijie @ 2012-10-18  6:22 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20121018032022.GB4378@S2101-09.ap.freescale.net>

? 2012?10?18? 11:20, Shawn Guo ??:
> On Tue, Oct 16, 2012 at 02:03:05PM +0800, Huang Shijie wrote:
>> Only we meet the following conditions, we can enable the DMA support for
>> auart:
>>
>> @@ -6,11 +6,18 @@ Required properties:
>>   - reg : Address and length of the register set for the device
>>   - interrupts : Should contain the auart interrupt numbers
>>
>> +Optional properties:
>> +- fsl,auart-dma-channel : The DMA channels, the first is for RX, the other
>> +			is for TX.
>> +- fsl,auart-enable-dma : Enable the DMA support for the auart.
>> +
> If we want to have it decided by device tree, can we drop the property
> and simply check if "fsl,auart-dma-channel" presents?
It's ok to me. fix it in next version.
>>   Example:
>>   auart0: serial at 8006a000 {
>>   	compatible = "fsl,imx28-auart";
>>   	reg =<0x8006a000 0x2000>;
>>   	interrupts =<112 70 71>;
>> +	fsl,auart-dma-channel =<8 9>;
>> +	fsl,auart-enable-dma;
>>   };
>>
>>   Note: Each auart port should have an alias correctly numbered in "aliases"
>> diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
>> index cd9ec1d..2271330 100644
>> --- a/drivers/tty/serial/mxs-auart.c
>> +++ b/drivers/tty/serial/mxs-auart.c
>> @@ -34,6 +34,8 @@
>>   #include<linux/io.h>
>>   #include<linux/pinctrl/consumer.h>
>>   #include<linux/of_device.h>
>> +#include<linux/dma-mapping.h>
>> +#include<linux/fsl/mxs-dma.h>
>>
>>   #include<asm/cacheflush.h>
>>
>> @@ -76,7 +78,15 @@
>>
>>   #define AUART_CTRL0_SFTRST			(1<<  31)
>>   #define AUART_CTRL0_CLKGATE			(1<<  30)
>> +#define AUART_CTRL0_RXTO_ENABLE			(1<<  27)
>> +#define AUART_CTRL0_RXTIMEOUT(v)		(((v)&  0x7ff)<<  16)
>> +#define AUART_CTRL0_XFER_COUNT(v)		((v)&  0xffff)
>>
>> +#define AUART_CTRL1_XFER_COUNT(v)		((v)&  0xffff)
>> +
>> +#define AUART_CTRL2_DMAONERR			(1<<  26)
>> +#define AUART_CTRL2_TXDMAE			(1<<  25)
>> +#define AUART_CTRL2_RXDMAE			(1<<  24)
>>   #define AUART_CTRL2_CTSEN			(1<<  15)
>>   #define AUART_CTRL2_RTSEN			(1<<  14)
>>   #define AUART_CTRL2_RTS				(1<<  11)
>> @@ -116,12 +126,15 @@
>>   #define AUART_STAT_BERR				(1<<  18)
>>   #define AUART_STAT_PERR				(1<<  17)
>>   #define AUART_STAT_FERR				(1<<  16)
>> +#define AUART_STAT_RXCOUNT_MASK			0xffff
>>
>>   static struct uart_driver auart_driver;
>>
>>   struct mxs_auart_port {
>>   	struct uart_port port;
>>
>> +#define MXS_AUART_DMA_CONFIG	0x1
>> +#define MXS_AUART_DMA_ENABLED	0x2
>>   	unsigned int flags;
>>   	unsigned int ctrl;
>>
>> @@ -130,16 +143,116 @@ struct mxs_auart_port {
>>   	struct clk *clk;
>>   	struct device *dev;
>>   	struct platform_device *pdev;
>> +
>> +	/* for DMA */
>> +	struct mxs_dma_data dma_data;
>> +	int dma_channel_rx, dma_channel_tx;
>> +	int dma_irq_rx, dma_irq_tx;
>> +	int dma_channel;
>> +
>> +	struct scatterlist tx_sgl;
>> +	struct dma_chan	*tx_dma_chan;
>> +	void *tx_dma_buf;
>> +
>> +	struct scatterlist rx_sgl;
>> +	struct dma_chan	*rx_dma_chan;
>> +	void *rx_dma_buf;
>>   };
>>
>> +static inline bool auart_dma_enabled(struct mxs_auart_port *s)
>> +{
>> +	return s->flags&  MXS_AUART_DMA_ENABLED;
>> +}
>> +
>>   static void mxs_auart_stop_tx(struct uart_port *u);
>>
>>   #define to_auart_port(u) container_of(u, struct mxs_auart_port, port)
>>
>> +static inline void mxs_auart_tx_chars(struct mxs_auart_port *s);
>> +
>> +static void dma_tx_callback(void *param)
>> +{
>> +	struct mxs_auart_port *s = param;
>> +	struct circ_buf *xmit =&s->port.state->xmit;
>> +
>> +	dma_unmap_sg(s->dev,&s->tx_sgl, 1, DMA_TO_DEVICE);
>> +
>> +	/* wake up the possible processes. */
>> +	if (uart_circ_chars_pending(xmit)<  WAKEUP_CHARS)
>> +		uart_write_wakeup(&s->port);
>> +
>> +	mxs_auart_tx_chars(s);
>> +}
>> +
>> +static int mxs_auart_dma_tx(struct mxs_auart_port *s, int size)
>> +{
>> +	struct dma_async_tx_descriptor *desc;
>> +	struct scatterlist *sgl =&s->tx_sgl;
>> +	struct dma_chan *channel = s->tx_dma_chan;
>> +	u32 pio[1];
> One element array looks strange to me.
got it.
>> +
>> +	/* [1] : send PIO. Note, the first pio word is CTRL1. */
>> +	pio[0] = AUART_CTRL1_XFER_COUNT(size);
>> +	desc = dmaengine_prep_slave_sg(channel, (struct scatterlist *)pio,
>> +					1, DMA_TRANS_NONE, 0);
>> +	if (!desc) {
>> +		dev_err(s->dev, "step 1 error\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	/* [2] : set DMA buffer. */
>> +	sg_init_one(sgl, s->tx_dma_buf, size);
>> +	dma_map_sg(s->dev, sgl, 1, DMA_TO_DEVICE);
>> +	desc = dmaengine_prep_slave_sg(channel, sgl,
>> +			1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
>> +	if (!desc) {
>> +		dev_err(s->dev, "step 2 error\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	/* [3] : submit the DMA */
>> +	desc->callback = dma_tx_callback;
>> +	desc->callback_param = s;
>> +	dmaengine_submit(desc);
>> +	dma_async_issue_pending(channel);
>> +	return 0;
>> +}
>> +
>>   static inline void mxs_auart_tx_chars(struct mxs_auart_port *s)
> I'm not sure why this function is inline from the beginning.  It
yes. The inline is not proper.

Best Regards
Huang Shijie

^ permalink raw reply

* [PATCH] dma: add new DMA control commands
From: Vinod Koul @ 2012-10-18  6:18 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1350538335-29026-1-git-send-email-b32955@freescale.com>

On Thu, 2012-10-18 at 13:32 +0800, Huang Shijie wrote:
> From: Huang Shijie <shijie8@gmail.com>
> 
> [1] Why add these new DMA control commands?
>     In mx6q, the gpmi-nand driver is the only user of the APBH-DMA. The dma clock
>     is enabled when we have successfully requested a DMA channel. So even when
>     the gpmi-nand driver does not work, the dma clock(apbh-dma) still runs
>     in high speed (198MHz). To save some power, it is better to disable the dma
>     clock when the dma device, such as gpmi-nand, is not working anymore.
>     When the dma device becomes work again, enable the dma clock again.
> 
> [2] add new DMA control commands: DMA_START/DMA_END
>     DMA_START: do some preprations to start the DMA engine, such as enable the
>                necessary clocks.
>     DMA_END: do some works to end the DMA engine, such as disable the
>                necessary clocks.
> 
> [3] This patch does not change any logic in i2c-mxs driver and mxs-pcm driver.
>     But for gpmi-nand driver, we will enable the the clock only when we select
>     the nand chip, and want to do some real jobs with the nand chip.
>     For mxs-mmc driver, disable the dma clock in the suspend; and enable the
>     dma clock in the resume.
> 
Why cant you do start (prepare clock etc) when you submit the descriptor
to dmaengine. Can be done in tx_submit callback.
Similarly remove the clock when dma transaction gets completed.

I don't think we need a new API for this, it needs to be handled by
driver on its own.

> Signed-off-by: Huang Shijie <b32955@freescale.com>
> ---
>  drivers/dma/mxs-dma.c                  |   17 +++++++++++++++++
>  drivers/i2c/busses/i2c-mxs.c           |   10 +++++++++-
>  drivers/mmc/host/mxs-mmc.c             |   19 ++++++++++++++++---
>  drivers/mtd/nand/gpmi-nand/gpmi-lib.c  |   10 ++++++++++
>  drivers/mtd/nand/gpmi-nand/gpmi-nand.c |   10 ++++++----
>  include/linux/dmaengine.h              |    6 ++++++
>  sound/soc/mxs/mxs-pcm.c                |   12 ++++++++++++
>  7 files changed, 76 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c
> index 9f02e79..89286f4 100644
> --- a/drivers/dma/mxs-dma.c
> +++ b/drivers/dma/mxs-dma.c
> @@ -384,6 +384,8 @@ static int mxs_dma_alloc_chan_resources(struct dma_chan *chan)
>  	/* the descriptor is ready */
>  	async_tx_ack(&mxs_chan->desc);
>  
> +	clk_disable_unprepare(mxs_dma->clk);
> +
>  	return 0;
>  
>  err_clk:
> @@ -399,6 +401,14 @@ static void mxs_dma_free_chan_resources(struct dma_chan *chan)
>  {
>  	struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
>  	struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
> +	int ret;
> +
> +	ret = clk_prepare_enable(mxs_dma->clk);
> +	if (ret) {
> +		dev_err(mxs_dma->dma_device.dev,
> +			"failed in enabling the dma clock\n");
> +		return;
> +	}
>  
>  	mxs_dma_disable_chan(mxs_chan);
>  
> @@ -597,9 +607,13 @@ static int mxs_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
>  		unsigned long arg)
>  {
>  	struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
> +	struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
>  	int ret = 0;
>  
>  	switch (cmd) {
> +	case DMA_START:
> +		ret = clk_prepare_enable(mxs_dma->clk);
> +		break;
>  	case DMA_TERMINATE_ALL:
>  		mxs_dma_reset_chan(mxs_chan);
>  		mxs_dma_disable_chan(mxs_chan);
> @@ -610,6 +624,9 @@ static int mxs_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
>  	case DMA_RESUME:
>  		mxs_dma_resume_chan(mxs_chan);
>  		break;
> +	case DMA_END:
> +		clk_disable_unprepare(mxs_dma->clk);
> +		break;
>  	default:
>  		ret = -ENOSYS;
>  	}
> diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
> index 1f58197..da1e881 100644
> --- a/drivers/i2c/busses/i2c-mxs.c
> +++ b/drivers/i2c/busses/i2c-mxs.c
> @@ -643,6 +643,12 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
>  			dev_err(dev, "Failed to request dma\n");
>  			return -ENODEV;
>  		}
> +		err = dmaengine_device_control(i2c->dmach, DMA_START, 0);
> +		if (err) {
> +			dma_release_channel(i2c->dmach);
> +			dev_err(dev, "Failed to start dma\n");
> +			return err;
> +		}
>  	}
>  
>  	platform_set_drvdata(pdev, i2c);
> @@ -680,8 +686,10 @@ static int __devexit mxs_i2c_remove(struct platform_device *pdev)
>  	if (ret)
>  		return -EBUSY;
>  
> -	if (i2c->dmach)
> +	if (i2c->dmach) {
> +		dmaengine_device_control(i2c->dmach, DMA_END, 0);
>  		dma_release_channel(i2c->dmach);
> +	}
>  
>  	writel(MXS_I2C_CTRL0_SFTRST, i2c->regs + MXS_I2C_CTRL0_SET);
>  
> diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
> index 80d1e6d..aa91830 100644
> --- a/drivers/mmc/host/mxs-mmc.c
> +++ b/drivers/mmc/host/mxs-mmc.c
> @@ -676,6 +676,9 @@ static int mxs_mmc_probe(struct platform_device *pdev)
>  			"%s: failed to request dma\n", __func__);
>  		goto out_clk_put;
>  	}
> +	ret = dmaengine_device_control(ssp->dmach, DMA_START, 0);
> +	if (ret)
> +		goto out_free_dma;
>  
>  	/* set mmc core parameters */
>  	mmc->ops = &mxs_mmc_ops;
> @@ -717,18 +720,20 @@ static int mxs_mmc_probe(struct platform_device *pdev)
>  	ret = devm_request_irq(&pdev->dev, irq_err, mxs_mmc_irq_handler, 0,
>  			       DRIVER_NAME, host);
>  	if (ret)
> -		goto out_free_dma;
> +		goto out_end_free_dma;
>  
>  	spin_lock_init(&host->lock);
>  
>  	ret = mmc_add_host(mmc);
>  	if (ret)
> -		goto out_free_dma;
> +		goto out_end_free_dma;
>  
>  	dev_info(mmc_dev(host->mmc), "initialized\n");
>  
>  	return 0;
>  
> +out_end_free_dma:
> +	dmaengine_device_control(ssp->dmach, DMA_END, 0);
>  out_free_dma:
>  	if (ssp->dmach)
>  		dma_release_channel(ssp->dmach);
> @@ -750,8 +755,10 @@ static int mxs_mmc_remove(struct platform_device *pdev)
>  
>  	platform_set_drvdata(pdev, NULL);
>  
> -	if (ssp->dmach)
> +	if (ssp->dmach) {
> +		dmaengine_device_control(ssp->dmach, DMA_END, 0);
>  		dma_release_channel(ssp->dmach);
> +	}
>  
>  	clk_disable_unprepare(ssp->clk);
>  	clk_put(ssp->clk);
> @@ -772,6 +779,7 @@ static int mxs_mmc_suspend(struct device *dev)
>  	ret = mmc_suspend_host(mmc);
>  
>  	clk_disable_unprepare(ssp->clk);
> +	dmaengine_device_control(ssp->dmach, DMA_END, 0);
>  
>  	return ret;
>  }
> @@ -784,8 +792,13 @@ static int mxs_mmc_resume(struct device *dev)
>  	int ret = 0;
>  
>  	clk_prepare_enable(ssp->clk);
> +	ret = dmaengine_device_control(ssp->dmach, DMA_START, 0);
> +	if (ret)
> +		return ret;
>  
>  	ret = mmc_resume_host(mmc);
> +	if (ret)
> +		dmaengine_device_control(ssp->dmach, DMA_END, 0);
>  
>  	return ret;
>  }
> diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
> index 3502acc..20ed3f3 100644
> --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
> +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
> @@ -958,6 +958,7 @@ void gpmi_begin(struct gpmi_nand_data *this)
>  	uint32_t       reg;
>  	unsigned int   dll_wait_time_in_us;
>  	struct gpmi_nfc_hardware_timing  hw;
> +	struct dma_chan *channel = get_dma_chan(this);
>  	int ret;
>  
>  	/* Enable the clock. */
> @@ -967,6 +968,12 @@ void gpmi_begin(struct gpmi_nand_data *this)
>  		goto err_out;
>  	}
>  
> +	ret = dmaengine_device_control(channel, DMA_START, 0);
> +	if (ret) {
> +		gpmi_disable_clk(this);
> +		goto err_out;
> +	}
> +
>  	/* Only initialize the timing once */
>  	if (this->flags & GPMI_TIMING_INIT_OK)
>  		return;
> @@ -1035,7 +1042,10 @@ err_out:
>  
>  void gpmi_end(struct gpmi_nand_data *this)
>  {
> +	struct dma_chan *channel = get_dma_chan(this);
> +
>  	gpmi_disable_clk(this);
> +	dmaengine_device_control(channel, DMA_END, 0);
>  }
>  
>  /* Clears a BCH interrupt. */
> diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
> index e2c56fc..5694d03 100644
> --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
> +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
> @@ -815,12 +815,14 @@ static void gpmi_select_chip(struct mtd_info *mtd, int chipnr)
>  	struct nand_chip *chip = mtd->priv;
>  	struct gpmi_nand_data *this = chip->priv;
>  
> -	if ((this->current_chip < 0) && (chipnr >= 0))
> +	if ((this->current_chip < 0) && (chipnr >= 0)) {
> +		/* set the current_chip before we call gpmi_begin(). */
> +		this->current_chip = chipnr;
>  		gpmi_begin(this);
> -	else if ((this->current_chip >= 0) && (chipnr < 0))
> +	} else if ((this->current_chip >= 0) && (chipnr < 0)) {
>  		gpmi_end(this);
> -
> -	this->current_chip = chipnr;
> +		this->current_chip = chipnr;
> +	}
>  }
>  
>  static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
> diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
> index d3201e4..79f864a 100644
> --- a/include/linux/dmaengine.h
> +++ b/include/linux/dmaengine.h
> @@ -199,6 +199,8 @@ enum dma_ctrl_flags {
>  /**
>   * enum dma_ctrl_cmd - DMA operations that can optionally be exercised
>   * on a running channel.
> + * @DMA_START: do some preprations to start the DMA engine, such as enable the
> + * necessary clocks.
>   * @DMA_TERMINATE_ALL: terminate all ongoing transfers
>   * @DMA_PAUSE: pause ongoing transfers
>   * @DMA_RESUME: resume paused transfer
> @@ -209,13 +211,17 @@ enum dma_ctrl_flags {
>   * command.
>   * @FSLDMA_EXTERNAL_START: this command will put the Freescale DMA controller
>   * into external start mode.
> + * @DMA_END: do some works to end the DMA engine, such as disable the
> + * necessary clocks.
>   */
>  enum dma_ctrl_cmd {
> +	DMA_START,
>  	DMA_TERMINATE_ALL,
>  	DMA_PAUSE,
>  	DMA_RESUME,
>  	DMA_SLAVE_CONFIG,
>  	FSLDMA_EXTERNAL_START,
> +	DMA_END,
>  };
>  
>  /**
> diff --git a/sound/soc/mxs/mxs-pcm.c b/sound/soc/mxs/mxs-pcm.c
> index f82d766..cfcc30f 100644
> --- a/sound/soc/mxs/mxs-pcm.c
> +++ b/sound/soc/mxs/mxs-pcm.c
> @@ -92,6 +92,7 @@ static int snd_mxs_open(struct snd_pcm_substream *substream)
>  {
>  	struct snd_soc_pcm_runtime *rtd = substream->private_data;
>  	struct mxs_pcm_dma_data *pcm_dma_data;
> +	struct dma_chan *chan;
>  	int ret;
>  
>  	pcm_dma_data = kzalloc(sizeof(*pcm_dma_data), GFP_KERNEL);
> @@ -107,6 +108,14 @@ static int snd_mxs_open(struct snd_pcm_substream *substream)
>  		return ret;
>  	}
>  
> +	chan = snd_dmaengine_pcm_get_chan(substream);
> +	ret = dmaengine_device_control(chan, DMA_START, (unsigned long)0);
> +	if (ret) {
> +		snd_dmaengine_pcm_close(substream);
> +		kfree(pcm_dma_data);
> +		return ret;
> +	}
> +
>  	snd_soc_set_runtime_hwparams(substream, &snd_mxs_hardware);
>  
>  	snd_dmaengine_pcm_set_data(substream, pcm_dma_data);
> @@ -117,7 +126,10 @@ static int snd_mxs_open(struct snd_pcm_substream *substream)
>  static int snd_mxs_close(struct snd_pcm_substream *substream)
>  {
>  	struct mxs_pcm_dma_data *pcm_dma_data = snd_dmaengine_pcm_get_data(substream);
> +	struct dma_chan *chan;
>  
> +	chan = snd_dmaengine_pcm_get_chan(substream);
> +	dmaengine_device_control(chan, DMA_END, 0);
>  	snd_dmaengine_pcm_close(substream);
>  	kfree(pcm_dma_data);
>  


-- 
~Vinod

^ permalink raw reply

* RT throttling and suspend/resume (was Re: [PATCH] i2c: omap: revert "i2c: omap: switch to threaded IRQ support")
From: Felipe Balbi @ 2012-10-18  5:51 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <87txtsitpt.fsf@deeprootsystems.com>

On Wed, Oct 17, 2012 at 04:06:54PM -0700, Kevin Hilman wrote:
> Felipe Balbi <balbi@ti.com> writes:
> 
> > On Wed, Oct 17, 2012 at 05:00:02PM +0300, Felipe Balbi wrote:
> >> 
> >> On Tue, Oct 16, 2012 at 02:39:50PM -0700, Kevin Hilman wrote:
> >> > + peterz, tglx
> >> > 
> >> > Felipe Balbi <balbi@ti.com> writes:
> >> > 
> >> > [...]
> >> > 
> >> > > The problem I see is that even though we properly return IRQ_WAKE_THREAD
> >> > > and wake_up_process() manages to wakeup the IRQ thread (it returns 1),
> >> > > the thread is never scheduled. To make things even worse, ouw irq thread
> >> > > runs once, but doesn't run on a consecutive call. Here's some (rather
> >> > > nasty) debug prints showing the problem:
> >> > 
> >> > [...]
> >> > 
> >> > >> [   88.721923] try_to_wake_up 1411
> >> > >> [   88.725189] ===> irq_wake_thread 139: IRQ 72 wake_up_process 0
> >> > >> [   88.731292] [sched_delayed] sched: RT throttling activated
> >> > 
> >> > This throttling message is the key one.
> >> > 
> >> > With RT throttling activated, the IRQ thread will not be run (it
> >> > eventually will be allowed much later on, but by then, the I2C xfers
> >> > have timed out.)
> >> > 
> >> > As a quick hack, the throttling can be disabled by seeting the
> >> > sched_rt_runtime to RUNTIME_INF:
> >> > 
> >> >         # sysctl -w kernel.sched_rt_runtime_us=-1
> >> > 
> >> > and a quick test shows that things go back to working as expected.  But
> >> > we still need to figure out why the throttling is hapenning...
> >> > 
> >> > So I started digging into why the RT runtime was so high, and noticed
> >> > that time spent in suspend was being counted as RT runtime!
> >> > 
> >> > So spending time in suspend anywhere near sched_rt_runtime (0.95s) will
> >> > cause the RT throttling to always be triggered, and thus prevent IRQ
> >> > threads from running in the resume path.  Ouch.
> >> > 
> >> > I think I'm already in over my head in the RT runtime stuff, but
> >> > counting the time spent in suspend as RT runtime smells like a bug to
> >> > me. no?
> >> > 
> >> > Peter? Thomas?
> >> 
> >> it looks like removing console output completely (echo 0 >
> >> /proc/sysrq-trigger) I don't see the issue anymore. Let me just run for
> >> a few more iterations to make sure what I'm saying is correct.
> >
> > Yeah, really looks like removing console output makes the problem go
> > away. Ran a few iterations and it always worked fine. Full logs attached
> 
> Removing console output during resume is going to significantly change
> the timing of what is happening during suspend/resume, so I suspect that
> combined with all your other debug prints is somehow masking the
> problem.  How log are you letting the system stay in suspend?

about 2 minutes

> That being said, I can still easily reproduce the problem, even with
> console output disabled.
> 
> With vanilla v3.7-rc1 + the debug patch below[1], with and without
> console output, I see RT throttling kicking in on resume, and the RT
> runtime on resume corresponds to the time spent in suspend.  Here's an
> example of debug output of my patch below after ~3 sec in suspend:
> 
> [   43.198028] sched_rt_runtime_exceeded: rt_time 2671752930 > runtime 950000000
> [   43.198028] update_curr_rt: RT runtime exceeded: irq/72-omap_i2c
> [   43.198059] update_curr_rt: RT runtime exceeded: irq/72-omap_i2c
> [   43.203704] [sched_delayed] sched: RT throttling activated
> 
> I see this rather consistently, and the rt_time value is always roughly the
> time I spent in suspend.
> 
> So the primary question remains: is RT runtime supposed to include the
> time spent suspended?  I suspect not. 

you might be right there, though we need Thomas or Peter to answer :-s

-- 
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121018/033fbaef/attachment.sig>

^ permalink raw reply

* [PATCH] ARM: OMAP2+: Only write the sysconfig on idle when necessary
From: Rajendra Nayak @ 2012-10-18  5:49 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <507F16F5.9020803@ti.com>

On Thursday 18 October 2012 02:07 AM, Jon Hunter wrote:
> Ok, thanks. Yes, only updating the register when the cache value changed
> would not work due to the possibility of context being lost. So
> Rajendra's change makes sense. However, I think there is room to
> optimise this.
>
> With this change, on idle, the cache value and register value are only
> updated when needed. This should be safe.
>
> Are you looking to go one step further and only update the sysconfig on
> enabling when the context has been lost? That would require more
> changes. This was a quick optimisation I saw when reviewing the code.
>
> Rajendra, let me know if you have any comments.

Makes sense to me. To handle the more generic case of avoiding all
reads and writes whenever possible, and making the cache really behave
like a cache, as Paul suggested, is certainly more work and more
importantly more testing, as it would rely heavily on the context lost 
counters to work correctly. I feel there is still some work needed
around those counters to make them more robust before we start heading
in that direction.

^ permalink raw reply

* [PATCH v2] arm: omap: move OMAP USB platform data to <linux/platform_data/omap-usb.h>
From: Felipe Balbi @ 2012-10-18  5:49 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20121017203404.GY15569@atomide.com>

Hi,

On Wed, Oct 17, 2012 at 01:34:04PM -0700, Tony Lindgren wrote:
> * Felipe Balbi <balbi@ti.com> [121017 08:54]:
> > In order to make single zImage work for ARM architecture,
> > we need to make sure we don't depend on private headers.
> > 
> > Move USB platform_data to <linux/platform_data/omap-usb.h>
> > and keep only internal functions in <plat/usb.h>.
> 
> Thanks, looks like I can't make this apply against v3.7-rc1:
> 
> patching file arch/arm/plat-omap/include/plat/usb.h
> Hunk #1 FAILED at 1.
> Hunk #2 FAILED at 26.
> Hunk #3 FAILED at 44.
> Hunk #4 FAILED at 65.
> Hunk #5 FAILED at 81.
> Hunk #6 succeeded at 28 with fuzz 2 (offset -128 lines).
> 5 out of 6 hunks FAILED -- rejects in file arch/arm/plat-omap/include/plat/usb.h
> 
> Can you please check it?

Are you sure you have a clean v3.7-rc1 ?

commit 9b1ebba0f43e7bf6a8fdd8aa84da65e5e0344fb7
Author: Felipe Balbi <balbi@ti.com>
Date:   Fri Sep 28 09:51:01 2012 +0300

    arm: omap: move OMAP USB platform data to <linux/platform_data/omap-usb.h>
    
    In order to make single zImage work for ARM architecture,
    we need to make sure we don't depend on private headers.
    
    Move USB platform_data to <linux/platform_data/omap-usb.h>
    and keep only internal functions in <plat/usb.h>.
    
    Signed-off-by: Felipe Balbi <balbi@ti.com>

commit ddffeb8c4d0331609ef2581d84de4d763607bd37
Author: Linus Torvalds <torvalds@linux-foundation.org>
Date:   Sun Oct 14 14:41:04 2012 -0700

    Linux 3.7-rc1


That's my branch. Patch is right on top of v3.7-rc1 commit.

-- 
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121018/0c4bdbcb/attachment-0001.sig>

^ permalink raw reply

* [PATCH] ARM: dts: AM33XX: Add tsl2550 ambient light sensor DT data
From: AnilKumar, Chimata @ 2012-10-18  5:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1348242551-21293-1-git-send-email-anilkumar@ti.com>

On Fri, Sep 21, 2012 at 21:19:11, AnilKumar, Chimata wrote:
> Add tsl2550 ambient light sensor DT data to am335x-evm.dts. In AM335x
> EVM tsl2550 ambient light sensor is connected to I2C2 bus. So this patch
> adds child node inside i2c2 node with i2c slave address.
> 
> TAOS tsl2550 sensor with two-wire SMBus serial interface. This patch
> also reduces I2C2 clock frequency to 100KHz from 400KHz because the
> maximum clock frequency of SMBus is 100KHz.
> 
> Signed-off-by: AnilKumar Ch <anilkumar@ti.com>
> ---
>  arch/arm/boot/dts/am335x-evm.dts |    7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
> index 3b1f313..d99aa0f 100644
> --- a/arch/arm/boot/dts/am335x-evm.dts
> +++ b/arch/arm/boot/dts/am335x-evm.dts
> @@ -49,7 +49,7 @@
>  
>  		i2c2: i2c at 4802a000 {
>  			status = "okay";
> -			clock-frequency = <400000>;
> +			clock-frequency = <100000>;
>  
>  			lis331dlh: lis331dlh at 18 {
>  				compatible = "st,lis331dlh", "st,lis3lv02d";
> @@ -79,6 +79,11 @@
>  				st,max-limit-z = <750>;
>  			};
>  
> +			tsl2550: tsl2550 at 39 {
> +				compatible = "taos,tsl2550";
> +				reg = <0x39>;
> +			};
> +
>  			tmp275: tmp275 at 48 {
>  				compatible = "ti,tmp275";
>  				reg = <0x48>;

Hi Tony/Benoit,

If there are no comments in this patch could you please take this in?

Thanks
AnilKumar

^ 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