aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRicardo Neri <ricardo.neri@ti.com>2011-11-27 17:09:58 -0500
committerTomi Valkeinen <tomi.valkeinen@ti.com>2012-01-05 03:34:48 -0500
commit80a485962807aae44a93197ee88854910bb935ad (patch)
tree1ccfba67a0625db1b8f34895535b5c3f30333d10
parent284cb318c8f84744f073d4f4d3820946afaf5442 (diff)
OMAPDSS: HDMI: Create function to enable HDMI audio
In order to separate clearly IP-specific code from general DSS code, a function for OMAP4 audio enable is created. This function is included in the HDMI IP ops to align with the current implementation of the DSS HDMI driver. This function is to be used by the ASoC HDMI audio codec. Signed-off-by: Ricardo Neri <ricardo.neri@ti.com> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
-rw-r--r--drivers/video/omap2/dss/dss_features.c4
-rw-r--r--drivers/video/omap2/dss/ti_hdmi.h10
-rw-r--r--drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c30
3 files changed, 31 insertions, 13 deletions
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c
index 5e4b829605da..afcb59301c37 100644
--- a/drivers/video/omap2/dss/dss_features.c
+++ b/drivers/video/omap2/dss/dss_features.c
@@ -472,6 +472,10 @@ static const struct ti_hdmi_ip_ops omap4_hdmi_functions = {
472 .dump_core = ti_hdmi_4xxx_core_dump, 472 .dump_core = ti_hdmi_4xxx_core_dump,
473 .dump_pll = ti_hdmi_4xxx_pll_dump, 473 .dump_pll = ti_hdmi_4xxx_pll_dump,
474 .dump_phy = ti_hdmi_4xxx_phy_dump, 474 .dump_phy = ti_hdmi_4xxx_phy_dump,
475#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
476 defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
477 .audio_enable = ti_hdmi_4xxx_wp_audio_enable,
478#endif
475 479
476}; 480};
477 481
diff --git a/drivers/video/omap2/dss/ti_hdmi.h b/drivers/video/omap2/dss/ti_hdmi.h
index 2c3443dabb14..7503f7f619a7 100644
--- a/drivers/video/omap2/dss/ti_hdmi.h
+++ b/drivers/video/omap2/dss/ti_hdmi.h
@@ -110,6 +110,11 @@ struct ti_hdmi_ip_ops {
110 110
111 void (*dump_phy)(struct hdmi_ip_data *ip_data, struct seq_file *s); 111 void (*dump_phy)(struct hdmi_ip_data *ip_data, struct seq_file *s);
112 112
113#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
114 defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
115 void (*audio_enable)(struct hdmi_ip_data *ip_data, bool start);
116#endif
117
113}; 118};
114 119
115struct hdmi_ip_data { 120struct hdmi_ip_data {
@@ -134,5 +139,8 @@ void ti_hdmi_4xxx_wp_dump(struct hdmi_ip_data *ip_data, struct seq_file *s);
134void ti_hdmi_4xxx_pll_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); 139void ti_hdmi_4xxx_pll_dump(struct hdmi_ip_data *ip_data, struct seq_file *s);
135void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); 140void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s);
136void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); 141void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s);
137 142#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
143 defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
144void ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data, bool enable);
145#endif
138#endif 146#endif
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c
index 3f74f55269bd..220e0ce5e5ef 100644
--- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c
+++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c
@@ -1204,35 +1204,41 @@ int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data,
1204 return 0; 1204 return 0;
1205} 1205}
1206 1206
1207void ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data, bool enable)
1208{
1209 REG_FLD_MOD(hdmi_av_base(ip_data),
1210 HDMI_CORE_AV_AUD_MODE, enable, 0, 0);
1211 REG_FLD_MOD(hdmi_wp_base(ip_data),
1212 HDMI_WP_AUDIO_CTRL, enable, 31, 31);
1213 REG_FLD_MOD(hdmi_wp_base(ip_data),
1214 HDMI_WP_AUDIO_CTRL, enable, 30, 30);
1215}
1216
1207int hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd, 1217int hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd,
1208 struct snd_soc_dai *dai) 1218 struct snd_soc_dai *dai)
1209{ 1219{
1210 struct snd_soc_pcm_runtime *rtd = substream->private_data; 1220 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1211 struct snd_soc_codec *codec = rtd->codec; 1221 struct snd_soc_codec *codec = rtd->codec;
1222 struct platform_device *pdev = to_platform_device(codec->dev);
1212 struct hdmi_ip_data *ip_data = snd_soc_codec_get_drvdata(codec); 1223 struct hdmi_ip_data *ip_data = snd_soc_codec_get_drvdata(codec);
1213 int err = 0; 1224 int err = 0;
1214 1225
1226 if (!(ip_data->ops) && !(ip_data->ops->audio_enable)) {
1227 dev_err(&pdev->dev, "Cannot enable/disable audio\n");
1228 return -ENODEV;
1229 }
1230
1215 switch (cmd) { 1231 switch (cmd) {
1216 case SNDRV_PCM_TRIGGER_START: 1232 case SNDRV_PCM_TRIGGER_START:
1217 case SNDRV_PCM_TRIGGER_RESUME: 1233 case SNDRV_PCM_TRIGGER_RESUME:
1218 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 1234 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1219 REG_FLD_MOD(hdmi_av_base(ip_data), 1235 ip_data->ops->audio_enable(ip_data, true);
1220 HDMI_CORE_AV_AUD_MODE, 1, 0, 0);
1221 REG_FLD_MOD(hdmi_wp_base(ip_data),
1222 HDMI_WP_AUDIO_CTRL, 1, 31, 31);
1223 REG_FLD_MOD(hdmi_wp_base(ip_data),
1224 HDMI_WP_AUDIO_CTRL, 1, 30, 30);
1225 break; 1236 break;
1226 1237
1227 case SNDRV_PCM_TRIGGER_STOP: 1238 case SNDRV_PCM_TRIGGER_STOP:
1228 case SNDRV_PCM_TRIGGER_SUSPEND: 1239 case SNDRV_PCM_TRIGGER_SUSPEND:
1229 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 1240 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
1230 REG_FLD_MOD(hdmi_av_base(ip_data), 1241 ip_data->ops->audio_enable(ip_data, false);
1231 HDMI_CORE_AV_AUD_MODE, 0, 0, 0);
1232 REG_FLD_MOD(hdmi_wp_base(ip_data),
1233 HDMI_WP_AUDIO_CTRL, 0, 30, 30);
1234 REG_FLD_MOD(hdmi_wp_base(ip_data),
1235 HDMI_WP_AUDIO_CTRL, 0, 31, 31);
1236 break; 1242 break;
1237 default: 1243 default:
1238 err = -EINVAL; 1244 err = -EINVAL;
->hostdata)->ctrl = 0; if (request_irq(instance->irq, scsi_sun3_intr, 0, "Sun3SCSI-5380", NULL)) { #ifndef REAL_DMA printk("scsi%d: IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); instance->irq = SCSI_IRQ_NONE; #else printk("scsi%d: IRQ%d not free, bailing out\n", instance->host_no, instance->irq); return 0; #endif } printk("scsi%d: Sun3 5380 at port %lX irq", instance->host_no, instance->io_port); if (instance->irq == SCSI_IRQ_NONE) printk ("s disabled"); else printk (" %d", instance->irq); printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", instance->can_queue, instance->cmd_per_lun, SUN3SCSI_PUBLIC_RELEASE); printk("\nscsi%d:", instance->host_no); NCR5380_print_options(instance); printk("\n"); dregs->csr = 0; udelay(SUN3_DMA_DELAY); dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR; udelay(SUN3_DMA_DELAY); dregs->fifo_count = 0; called = 1; #ifdef RESET_BOOT sun3_scsi_reset_boot(instance); #endif return 1; } int sun3scsi_release (struct Scsi_Host *shpnt) { if (shpnt->irq != SCSI_IRQ_NONE) free_irq (shpnt->irq, NULL); iounmap((void *)sun3_scsi_regp); return 0; } #ifdef RESET_BOOT /* * Our 'bus reset on boot' function */ static void sun3_scsi_reset_boot(struct Scsi_Host *instance) { unsigned long end; NCR5380_local_declare(); NCR5380_setup(instance); /* * Do a SCSI reset to clean up the bus during initialization. No * messing with the queues, interrupts, or locks necessary here. */ printk( "Sun3 SCSI: resetting the SCSI bus..." ); /* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */ // sun3_disable_irq( IRQ_SUN3_SCSI ); /* get in phase */ NCR5380_write( TARGET_COMMAND_REG, PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) )); /* assert RST */ NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST ); /* The min. reset hold time is 25us, so 40us should be enough */ udelay( 50 ); /* reset RST and interrupt */ NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); NCR5380_read( RESET_PARITY_INTERRUPT_REG ); for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); ) barrier(); /* switch on SCSI IRQ again */ // sun3_enable_irq( IRQ_SUN3_SCSI ); printk( " done\n" ); } #endif const char * sun3scsi_info (struct Scsi_Host *spnt) { return ""; } // safe bits for the CSR #define CSR_GOOD 0x060f static irqreturn_t scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp) { unsigned short csr = dregs->csr; int handled = 0; if(csr & ~CSR_GOOD) { if(csr & CSR_DMA_BUSERR) { printk("scsi%d: bus error in dma\n", default_instance->host_no); } if(csr & CSR_DMA_CONFLICT) { printk("scsi%d: dma conflict\n", default_instance->host_no); } handled = 1; } if(csr & (CSR_SDB_INT | CSR_DMA_INT)) { NCR5380_intr(irq, dummy, fp); handled = 1; } return IRQ_RETVAL(handled); } /* * Debug stuff - to be called on NMI, or sysrq key. Use at your own risk; * reentering NCR5380_print_status seems to have ugly side effects */ /* this doesn't seem to get used at all -- sam */ #if 0 void sun3_sun3_debug (void) { unsigned long flags; NCR5380_local_declare(); if (default_instance) { local_irq_save(flags); NCR5380_print_status(default_instance); local_irq_restore(flags); } } #endif /* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */ static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int write_flag) { #ifdef OLDDMA if(write_flag) memcpy(dmabuf, data, count); else { sun3_dma_orig_addr = data; sun3_dma_orig_count = count; } #else void *addr; if(sun3_dma_orig_addr != NULL) dvma_unmap(sun3_dma_orig_addr); // addr = sun3_dvma_page((unsigned long)data, (unsigned long)dmabuf); addr = (void *)dvma_map((unsigned long) data, count); sun3_dma_orig_addr = addr; sun3_dma_orig_count = count; #endif dregs->fifo_count = 0; sun3_udc_write(UDC_RESET, UDC_CSR); /* reset fifo */ dregs->csr &= ~CSR_FIFO; dregs->csr |= CSR_FIFO; /* set direction */ if(write_flag) dregs->csr |= CSR_SEND; else dregs->csr &= ~CSR_SEND; /* byte count for fifo */ dregs->fifo_count = count; sun3_udc_write(UDC_RESET, UDC_CSR); /* reset fifo */ dregs->csr &= ~CSR_FIFO; dregs->csr |= CSR_FIFO; if(dregs->fifo_count != count) { printk("scsi%d: fifo_mismatch %04x not %04x\n", default_instance->host_no, dregs->fifo_count, (unsigned int) count); NCR5380_print(default_instance); } /* setup udc */ #ifdef OLDDMA udc_regs->addr_hi = ((dvma_vtob(dmabuf) & 0xff0000) >> 8); udc_regs->addr_lo = (dvma_vtob(dmabuf) & 0xffff); #else udc_regs->addr_hi = (((unsigned long)(addr) & 0xff0000) >> 8); udc_regs->addr_lo = ((unsigned long)(addr) & 0xffff); #endif udc_regs->count = count/2; /* count in words */ udc_regs->mode_hi = UDC_MODE_HIWORD; if(write_flag) { if(count & 1) udc_regs->count++; udc_regs->mode_lo = UDC_MODE_LSEND; udc_regs->rsel = UDC_RSEL_SEND; } else { udc_regs->mode_lo = UDC_MODE_LRECV; udc_regs->rsel = UDC_RSEL_RECV; } /* announce location of regs block */ sun3_udc_write(((dvma_vtob(udc_regs) & 0xff0000) >> 8), UDC_CHN_HI); sun3_udc_write((dvma_vtob(udc_regs) & 0xffff), UDC_CHN_LO); /* set dma master on */ sun3_udc_write(0xd, UDC_MODE); /* interrupt enable */ sun3_udc_write(UDC_INT_ENABLE, UDC_CSR); return count; } static inline unsigned long sun3scsi_dma_count(struct Scsi_Host *instance) { unsigned short resid; dregs->udc_addr = 0x32; udelay(SUN3_DMA_DELAY); resid = dregs->udc_data; udelay(SUN3_DMA_DELAY); resid *= 2; return (unsigned long) resid; } static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance) { return last_residual; } static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, Scsi_Cmnd *cmd, int write_flag) { if(cmd->request->flags & REQ_CMD) return wanted; else return 0; } static inline int sun3scsi_dma_start(unsigned long count, unsigned char *data) { sun3_udc_write(UDC_CHN_START, UDC_CSR); return 0; } /* clean up after our dma is done */ static int sun3scsi_dma_finish(int write_flag) { unsigned short count; unsigned short fifo; int ret = 0; sun3_dma_active = 0; #if 1 // check to empty the fifo on a read if(!write_flag) { int tmo = 20000; /* .2 sec */ while(1) { if(dregs->csr & CSR_FIFO_EMPTY) break; if(--tmo <= 0) { printk("sun3scsi: fifo failed to empty!\n"); return 1; } udelay(10); } } #endif count = sun3scsi_dma_count(default_instance); #ifdef OLDDMA /* if we've finished a read, copy out the data we read */ if(sun3_dma_orig_addr) { /* check for residual bytes after dma end */ if(count && (NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | BASR_ACK))) { printk("scsi%d: sun3_scsi_finish: read overrun baby... ", default_instance->host_no); printk("basr now %02x\n", NCR5380_read(BUS_AND_STATUS_REG)); ret = count; } /* copy in what we dma'd no matter what */ memcpy(sun3_dma_orig_addr, dmabuf, sun3_dma_orig_count); sun3_dma_orig_addr = NULL; } #else fifo = dregs->fifo_count; last_residual = fifo; /* empty bytes from the fifo which didn't make it */ if((!write_flag) && (count - fifo) == 2) { unsigned short data; unsigned char *vaddr; data = dregs->fifo_data; vaddr = (unsigned char *)dvma_btov(sun3_dma_orig_addr); vaddr += (sun3_dma_orig_count - fifo); vaddr[-2] = (data & 0xff00) >> 8; vaddr[-1] = (data & 0xff); } dvma_unmap(sun3_dma_orig_addr); sun3_dma_orig_addr = NULL; #endif sun3_udc_write(UDC_RESET, UDC_CSR); dregs->fifo_count = 0; dregs->csr &= ~CSR_SEND; /* reset fifo */ dregs->csr &= ~CSR_FIFO; dregs->csr |= CSR_FIFO; sun3_dma_setup_done = NULL; return ret; } #include "sun3_NCR5380.c" static Scsi_Host_Template driver_template = { .name = SUN3_SCSI_NAME, .detect = sun3scsi_detect, .release = sun3scsi_release, .info = sun3scsi_info, .queuecommand = sun3scsi_queue_command, .eh_abort_handler = sun3scsi_abort, .eh_bus_reset_handler = sun3scsi_bus_reset, .can_queue = CAN_QUEUE, .this_id = 7, .sg_tablesize = SG_TABLESIZE, .cmd_per_lun = CMD_PER_LUN, .use_clustering = DISABLE_CLUSTERING }; #include "scsi_module.c" MODULE_LICENSE("GPL");