@@ -76,10 +76,17 @@ static struct dma_channel *dma_channel_allocate(struct dma_controller *c,
{
struct musb_dma_controller *controller = container_of(c,
struct musb_dma_controller, controller);
+ struct musb *musb = controller->private_data;
struct musb_dma_channel *musb_channel = NULL;
struct dma_channel *channel = NULL;
u8 bit;
+ if (!controller->used_channels) {
+ spin_unlock(&musb->lock);
+ pm_runtime_get_sync(musb->controller);
+ spin_lock(&musb->lock);
+ }
+
for (bit = 0; bit < MUSB_HSDMA_CHANNELS; bit++) {
if (!(controller->used_channels & (1 << bit))) {
controller->used_channels |= (1 << bit);
@@ -105,15 +112,25 @@ static struct dma_channel *dma_channel_allocate(struct dma_controller *c,
static void dma_channel_release(struct dma_channel *channel)
{
struct musb_dma_channel *musb_channel = channel->private_data;
+ struct musb_dma_controller *controller = musb_channel->controller;
+ struct musb *musb = controller->private_data;
+ u8 prev_used_channels;
channel->actual_len = 0;
musb_channel->start_addr = 0;
musb_channel->len = 0;
- musb_channel->controller->used_channels &=
- ~(1 << musb_channel->idx);
+ prev_used_channels = controller->used_channels;
+ controller->used_channels &= ~(1 << musb_channel->idx);
channel->status = MUSB_DMA_STATUS_UNKNOWN;
+
+ /* Only _put() when going from 1 channel to 0 channels */
+ if (prev_used_channels && !controller->used_channels) {
+ spin_unlock(&musb->lock);
+ pm_runtime_put(musb->controller);
+ spin_lock(&musb->lock);
+ }
}
static void configure_channel(struct dma_channel *channel,
</PATCH>
I also have a simpler version that calls pm_runtime every time those
routines are called. Either way, the gadget code resets the device
and it doesn't work. I don't understand the code well enough to know
why and I don't have time to pursue it right now.
In the meantime, if pm_runtime calls are added to the start() and stop()
hooks of the DMA driver, it will work fine. The problem with putting the
pm_runtime calls there is that it will stay powered on even when DMA isn't
being used. This patch works for me on the am37x EVM:
<PATCH>
@@ -39,7 +39,12 @@
static int dma_controller_start(struct dma_controller *c)
{
- /* nothing to do */
+ struct musb_dma_controller *controller = container_of(c,
+ struct musb_dma_controller, controller);
+ struct musb *musb = controller->private_data;
+
+ pm_runtime_get_sync(musb->controller);
+
return 0;
}
@@ -68,6 +73,8 @@ static int dma_controller_stop(struct dma_controller *c)
}
}
+ pm_runtime_put(musb->controller);
+
return 0;
}