#define CIP_FMT_AM             0x10
 #define AMDTP_FDF_NO_DATA      0xff
 
-/* TODO: make these configurable */
-#define INTERRUPT_INTERVAL     16
-
 // For iso header, tstamp and 2 CIP header.
 #define IR_CTX_HEADER_SIZE_CIP         16
 // For iso header and tstamp.
                snd_pcm_period_elapsed(pcm);
 }
 
-static int queue_packet(struct amdtp_stream *s, struct fw_iso_packet *params)
+static int queue_packet(struct amdtp_stream *s, struct fw_iso_packet *params,
+                       bool sched_irq)
 {
        int err;
 
-       params->interrupt = IS_ALIGNED(s->packet_index + 1, INTERRUPT_INTERVAL);
+       params->interrupt = sched_irq;
        params->tag = s->tag;
        params->sy = 0;
 
 }
 
 static inline int queue_out_packet(struct amdtp_stream *s,
-                                  struct fw_iso_packet *params)
+                                  struct fw_iso_packet *params, bool sched_irq)
 {
        params->skip =
                !!(params->header_length == 0 && params->payload_length == 0);
-       return queue_packet(s, params);
+       return queue_packet(s, params, sched_irq);
 }
 
 static inline int queue_in_packet(struct amdtp_stream *s,
-                                 struct fw_iso_packet *params)
+                                 struct fw_iso_packet *params, bool sched_irq)
 {
        // Queue one packet for IR context.
        params->header_length = s->ctx_data.tx.ctx_header_size;
        params->payload_length = s->ctx_data.tx.max_ctx_payload_length;
        params->skip = false;
-       return queue_packet(s, params);
+       return queue_packet(s, params, sched_irq);
 }
 
 static void generate_cip_header(struct amdtp_stream *s, __be32 cip_header[2],
 {
        struct amdtp_stream *s = private_data;
        const __be32 *ctx_header = header;
+       unsigned int events_per_period = s->events_per_period;
+       unsigned int event_count = s->event_count;
        unsigned int packets;
        int i;
 
                        struct fw_iso_packet params;
                        __be32 header[IT_PKT_HEADER_SIZE_CIP / sizeof(__be32)];
                } template = { {0}, {0} };
+               bool sched_irq = false;
 
                if (s->ctx_data.rx.syt_override < 0)
                        syt = desc->syt;
                                    desc->data_blocks, desc->data_block_counter,
                                    syt, i);
 
-               if (queue_out_packet(s, &template.params) < 0) {
+               event_count += desc->data_blocks;
+               if (event_count >= events_per_period) {
+                       event_count -= events_per_period;
+                       sched_irq = true;
+               }
+
+               if (queue_out_packet(s, &template.params, sched_irq) < 0) {
                        cancel_stream(s);
                        return;
                }
        }
 
+       s->event_count = event_count;
+
        fw_iso_context_queue_flush(s->context);
 }
 
                               void *private_data)
 {
        struct amdtp_stream *s = private_data;
-       unsigned int packets;
        __be32 *ctx_header = header;
+       unsigned int events_per_period = s->events_per_period;
+       unsigned int event_count = s->event_count;
+       unsigned int packets;
        int i;
        int err;
 
        }
 
        for (i = 0; i < packets; ++i) {
+               const struct pkt_desc *desc = s->pkt_descs + i;
                struct fw_iso_packet params = {0};
+               bool sched_irq = false;
+
+               if (err >= 0) {
+                       event_count += desc->data_blocks;
+                       if (event_count >= events_per_period) {
+                               event_count -= events_per_period;
+                               sched_irq = true;
+                       }
+               } else {
+                       sched_irq =
+                               !((s->packet_index + 1) % s->idle_irq_interval);
+               }
 
-               if (queue_in_packet(s, ¶ms) < 0) {
+               if (queue_in_packet(s, ¶ms, sched_irq) < 0) {
                        cancel_stream(s);
                        return;
                }
        }
 
+       s->event_count = event_count;
+
        fw_iso_context_queue_flush(s->context);
 }
 
                [CIP_SFC_176400] = {  0,   67 },
        };
        unsigned int events_per_buffer = d->events_per_buffer;
+       unsigned int events_per_period = d->events_per_period;
        unsigned int ctx_header_size;
        unsigned int max_ctx_payload_size;
        enum dma_data_direction dir;
                        max_ctx_payload_size -= IT_PKT_HEADER_SIZE_CIP;
        }
 
+       // This is a case that AMDTP streams in domain run just for MIDI
+       // substream. Use the number of events equivalent to 10 msec as
+       // interval of hardware IRQ.
+       if (events_per_period == 0)
+               events_per_period = amdtp_rate_table[s->sfc] / 100;
        if (events_per_buffer == 0)
-               events_per_buffer = INTERRUPT_INTERVAL * 3;
+               events_per_buffer = events_per_period * 3;
 
+       s->idle_irq_interval =
+                       DIV_ROUND_UP(CYCLES_PER_SECOND * events_per_period,
+                                    amdtp_rate_table[s->sfc]);
        s->queue_size = DIV_ROUND_UP(CYCLES_PER_SECOND * events_per_buffer,
                                     amdtp_rate_table[s->sfc]);
+       s->events_per_period = events_per_period;
+       s->event_count = 0;
 
        err = iso_packets_buffer_init(&s->buffer, s->unit, s->queue_size,
                                      max_ctx_payload_size, dir);
        s->packet_index = 0;
        do {
                struct fw_iso_packet params;
+               bool sched_irq;
+
+               sched_irq = !((s->packet_index + 1) % s->idle_irq_interval);
                if (s->direction == AMDTP_IN_STREAM) {
-                       err = queue_in_packet(s, ¶ms);
+                       err = queue_in_packet(s, ¶ms, sched_irq);
                } else {
                        params.header_length = 0;
                        params.payload_length = 0;
-                       err = queue_out_packet(s, ¶ms);
+                       err = queue_out_packet(s, ¶ms, sched_irq);
                }
                if (err < 0)
                        goto err_pkt_descs;