From 37cc61c5a8045d018c051556cea12f6dff0fb278 Mon Sep 17 00:00:00 2001 From: Renaud de Chivre Date: Thu, 3 May 2012 14:12:40 +0200 Subject: [PATCH] Audio Comms I2S Driver : update for MRFL BZ: 30374 SSP driver update for Merrifield platform support. Change-Id: I3c4066064f066f335d02140c40ceb2bf46cbcb8e Signed-off-by: Renaud de Chivre Reviewed-on: http://android.intel.com:8080/42557 Reviewed-by: Mendi, EduardoX Tested-by: Mendi, EduardoX Reviewed-by: Gross, Mark Reviewed-by: buildbot Tested-by: buildbot --- sound/pci/intel_mid_i2s/intel_mid_i2s.c | 180 +++++++++++++++++++++++++++++--- sound/pci/intel_mid_i2s/intel_mid_i2s.h | 57 ++++++++++ 2 files changed, 221 insertions(+), 16 deletions(-) diff --git a/sound/pci/intel_mid_i2s/intel_mid_i2s.c b/sound/pci/intel_mid_i2s/intel_mid_i2s.c index ea87929..38f8d7c 100644 --- a/sound/pci/intel_mid_i2s/intel_mid_i2s.c +++ b/sound/pci/intel_mid_i2s/intel_mid_i2s.c @@ -30,6 +30,10 @@ #include #include #include +#ifdef __MRFL_SPECIFIC__ +#include +#endif + #include #include #include "intel_mid_i2s.h" @@ -40,8 +44,19 @@ MODULE_DESCRIPTION("Intel MID I2S/PCM SSP Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION("1.0.4"); + #define CLOCK_19200_KHZ 19200000 + +#ifdef __MRFL_SPECIFIC_TMP__ +/* FIXME: use of lpeshim_base_address should be + * avoided and replaced by a call to SST driver that will + * take care to access LPE Shim registers */ + +/* LPE Shim registers base address (needed for HW IRQ acknowledge) */ +static void __iomem *lpeshim_base_address; +#endif /* __MRFL_SPECIFIC_TMP__ */ + /* * Currently this limit to ONE modem on platform */ @@ -67,6 +82,7 @@ static DEFINE_PCI_DEVICE_TABLE(pci_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, MFLD_SSP0_DEVICE_ID) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, CLV_SSP1_DEVICE_ID) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, CLV_SSP0_DEVICE_ID) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, MRFL_SSP_DEVICE_ID) }, { 0, }, /* terminate list */ }; @@ -1633,8 +1649,26 @@ static void ssp1_dump_registers(struct intel_mid_i2s_hdl *drv_data) dev_dbg(ddbg, "dump SSTSS=0x%08X\n", status); status = read_SSACD(reg); dev_dbg(ddbg, "dump SSACD=0x%08X\n", status); + +#ifdef __MRFL_SPECIFIC__ + status = read_SSCR2(reg); + dev_dbg(ddbg, "dump SSCR2=0x%08X\n", status); + status = read_SSFS(reg); + dev_dbg(ddbg, "dump SSFS=0x%08X\n", status); + status = read_SFIFOL(reg); + dev_dbg(ddbg, "dump SFIFOL=0x%08X\n", status); + status = read_SFIFOTT(reg); + dev_dbg(ddbg, "dump SFIFOTT=0x%08X\n", status); + status = read_SSCR3(reg); + dev_dbg(ddbg, "dump SSCR3=0x%08X\n", status); + status = read_SSCR4(reg); + dev_dbg(ddbg, "dump SSCR4=0x%08X\n", status); + status = read_SSCR5(reg); + dev_dbg(ddbg, "dump SSCR5=0x%08X\n", status); +#endif /* __MRFL_SPECIFIC__ */ } + /** * i2s_irq(): function that handles the SSP Interrupts (errors) * @irq : IRQ Number @@ -1659,6 +1693,10 @@ static irqreturn_t i2s_irq(int irq, void *dev_id) u32 sssr_masked = 0; /* SSSR bits that need to be cleared after event handling */ u32 sssr_clr_mask = 0; +#ifdef __MRFL_SPECIFIC__ + /* SSSR register content */ + u32 isrx = 0; +#endif /* __MRFL_SPECIFIC__ */ #ifdef CONFIG_PM_SLEEP if (ddbg->power.is_prepared) @@ -1727,6 +1765,17 @@ static irqreturn_t i2s_irq(int irq, void *dev_id) /* Clear sticky bits */ write_SSSR((sssr & sssr_clr_mask), reg); +#ifdef __MRFL_SPECIFIC_TMP__ + /* FIXME: use of fixed addresses should be + * replaced by a call to SST driver that will + * take care to access LPE Shim registers */ + + /* Clear LPE sticky bits depending on SSP instance */ + isrx = LPE_ISRX_IAPIS_SSP0_MASK << (LPE_ISRX_IAPIS_SSP0_SHIFT + + drv_data->device_instance); + write_LPE_ISRX(isrx, lpeshim_base_address); +#endif /* __MRFL_SPECIFIC_TMP__ */ + i2s_irq_return: return irq_status; } @@ -1776,7 +1825,13 @@ irqreturn_t i2s_irq_handle_RFS(struct intel_mid_i2s_hdl *drv_data, u32 sssr) /* Schedule irq thread for final treatment * in i2s_irq_deferred */ set_bit(I2S_PORT_COMPLETE_READ, &drv_data->flags); +#ifndef __MRFL_SPECIFIC_TMP__ irq_status = IRQ_WAKE_THREAD; +#else /* __MRFL_SPECIFIC_TMP__ */ + /* FIXME: + * remove when threaded irq will work on MRFL kernel */ + irq_status = i2s_irq_deferred(drv_data->irq, (void *)drv_data); +#endif /* __MRFL_SPECIFIC_TMP__ */ } i2s_irq_handle_RFS_return: @@ -1829,7 +1884,13 @@ irqreturn_t i2s_irq_handle_TFS(struct intel_mid_i2s_hdl *drv_data, u32 sssr) /* Schedule irq thread for final treatment * in i2s_irq_deferred */ set_bit(I2S_PORT_COMPLETE_WRITE, &drv_data->flags); +#ifndef __MRFL_SPECIFIC_TMP__ irq_status = IRQ_WAKE_THREAD; +#else /* __MRFL_SPECIFIC_TMP__ */ + /* FIXME: + * remove when threaded irq will work on MRFL kernel */ + irq_status = i2s_irq_deferred(drv_data->irq, (void *)drv_data); +#endif /* __MRFL_SPECIFIC_TMP__*/ } i2s_irq_handle_TFS_return: @@ -2244,6 +2305,9 @@ static void set_ssp_i2s_hw(struct intel_mid_i2s_hdl *drv_data, u32 sssr = 0; u32 ssacd = 0; u32 sscr0_scr; +#ifdef __MRFL_SPECIFIC__ + u32 sfifott = 0; +#endif /* __MRFL_SPECIFIC__ */ u8 frame_rate_divider; /* Get the SSP Settings */ @@ -2363,6 +2427,14 @@ static void set_ssp_i2s_hw(struct intel_mid_i2s_hdl *drv_data, | (SSSR_PINT_MASK << SSSR_PINT_SHIFT) | (SSSR_ROR_MASK << SSSR_ROR_SHIFT); +#ifdef __MRFL_SPECIFIC__ + sfifott = replace_SFIFOTT_RFT(sfifott, + SSCR1_RxTresh(ps_settings->ssp_rx_fifo_threshold)); + sfifott = replace_SFIFOTT_TFT(sfifott, + SSCR1_TxTresh(ps_settings->ssp_tx_fifo_threshold)); + dev_dbg(ddbg, "WRITE SFIFOTT: 0x%08X\n", sfifott); +#endif /* __MRFL_SPECIFIC__ */ + /* disable SSP */ clear_SSCR0_reg(reg, SSE); dev_dbg(ddbg, "WRITE SSCR0 DISABLE\n"); @@ -2379,6 +2451,9 @@ static void set_ssp_i2s_hw(struct intel_mid_i2s_hdl *drv_data, write_SSTSA(sstsa, reg); write_SSRSA(ssrsa, reg); write_SSACD(ssacd, reg); +#ifdef __MRFL_SPECIFIC__ + write_SFIFOTT(sfifott, reg); +#endif /* __MRFL_SPECIFIC__ */ /* set the time out for the reception */ write_SSTO(0, reg); @@ -2448,6 +2523,24 @@ intel_mid_i2s_find_usage(struct pci_dev *pdev, } } #endif +#ifdef __MRFL_SPECIFIC_TMP__ + /* FIXME: will be remove when correct ADID generated in PCI table */ + if (*usage == SSP_USAGE_UNASSIGNED) { + dev_warn(&(pdev->dev), "Incorrect ADID: MRFL WA => assign 1\n"); + + switch (drv_data->paddr) { + case MRFL_SSP0_REG_BASE_ADDRESS: + *usage = SSP_USAGE_MODEM; + break; + case MRFL_SSP1_REG_BASE_ADDRESS: + *usage = SSP_USAGE_BLUETOOTH_FM; + break; + case MRFL_SSP2_REG_BASE_ADDRESS: + /* Won't probe : no usage */ + break; + } + } +#endif /* __MRFL_SPECIFIC_TMP__ */ if (*usage == SSP_USAGE_UNASSIGNED) { dev_info((&pdev->dev), @@ -2474,6 +2567,28 @@ intel_mid_i2s_find_usage(struct pci_dev *pdev, case CLV_SSP1_DEVICE_ID: drv_data->device_instance = SSP1_INSTANCE; break; + + case MRFL_SSP_DEVICE_ID: +#ifdef __MRFL_SPECIFIC_TMP__ + /* FIXME: use of MRFL_SSPx_REG_BASE_ADDRESS should be + * avoided by PCI table reorganization which allow to + * determine SSP # from PCI info */ + + /* Get device instance using register base address */ + switch (drv_data->paddr) { + case MRFL_SSP0_REG_BASE_ADDRESS: + drv_data->device_instance = SSP0_INSTANCE; + break; + case MRFL_SSP1_REG_BASE_ADDRESS: + drv_data->device_instance = SSP1_INSTANCE; + break; + case MRFL_SSP2_REG_BASE_ADDRESS: + drv_data->device_instance = SSP2_INSTANCE; + break; + } + break; +#endif /* __MRFL_SPECIFIC_TMP__ */ + default: dev_err(&(pdev->dev), "Can not determine device instance (PCI ID:%04x)\n", @@ -2482,10 +2597,6 @@ intel_mid_i2s_find_usage(struct pci_dev *pdev, goto err_find_usage; } - status = pci_enable_device(pdev); - if (status) - dev_err((&pdev->dev), "Can not enable device.Err=%d\n", status); - err_find_usage: return status; } @@ -2515,20 +2626,25 @@ static int intel_mid_i2s_probe(struct pci_dev *pdev, } dev_info((&pdev->dev), "Detected PCI SSP (ID: %04x:%04x)\n", pdev->vendor, pdev->device); - status = intel_mid_i2s_find_usage(pdev, drv_data, &usage, &ssp_fs_pin); - if (status) + + /* Enable device */ + status = pci_enable_device(pdev); + if (status) { + dev_err((&pdev->dev), "Can not enable device.Err=%d\n", status); goto err_i2s_probe0; + } mutex_init(&drv_data->mutex); drv_data->pdev = pdev; - drv_data->usage = usage; + /* * Get basic io resource and map it for SSP1 [BAR=0] */ if ((pdev->device == MFLD_SSP0_DEVICE_ID) || (pdev->device == MFLD_SSP1_DEVICE_ID) || (pdev->device == CLV_SSP0_DEVICE_ID) || - (pdev->device == CLV_SSP1_DEVICE_ID)) { + (pdev->device == CLV_SSP1_DEVICE_ID) || + (pdev->device == MRFL_SSP_DEVICE_ID)) { drv_data->paddr = pci_resource_start(pdev, MRST_SSP_BAR); drv_data->iolen = pci_resource_len(pdev, MRST_SSP_BAR); status = pci_request_region(pdev, MRST_SSP_BAR, @@ -2559,6 +2675,13 @@ static int intel_mid_i2s_probe(struct pci_dev *pdev, dev_dbg(&(pdev->dev), "ioaddr = : %p\n", drv_data->ioaddr); + /* Find SSP usage */ + status = intel_mid_i2s_find_usage(pdev, drv_data, &usage, &ssp_fs_pin); + if (status) + goto err_i2s_probe3; + + drv_data->usage = usage; + /* prepare for DMA channel allocation */ /* get the pci_dev structure pointer */ switch (pdev->device) { @@ -2576,6 +2699,12 @@ static int intel_mid_i2s_probe(struct pci_dev *pdev, NULL); break; + case MRFL_SSP_DEVICE_ID: + drv_data->dmac1 = pci_get_device(PCI_VENDOR_ID_INTEL, + MRFL_LPE_DMA_DEVICE_ID, + NULL); + break; + default: dev_err(&pdev->dev, "Don't know dma device ID for this SSP PCDID=%x\n", @@ -2603,6 +2732,7 @@ static int intel_mid_i2s_probe(struct pci_dev *pdev, | (SSCR1_TTE_MASK << SSCR1_TTE_SHIFT), drv_data->ioaddr); +#ifndef __MRFL_SPECIFIC__ /* WA not required for MRFL */ /* * Switch the SSP_FS pin from GPIO Input Mode * to functional Mode @@ -2624,19 +2754,31 @@ static int intel_mid_i2s_probe(struct pci_dev *pdev, dev_dbg(&pdev->dev, "SET GPIO_A0N %d to %d Mode\n", ssp_fs_pin.ssp_fs_gpio_mapping, ssp_fs_pin.ssp_fs_mode); +#endif /* __MRFL_SPECIFIC__ */ /* Attach to IRQ */ drv_data->irq = pdev->irq; +#ifndef __MRFL_SPECIFIC_TMP__ dev_dbg(&(pdev->dev), "attaching to IRQ: %04x\n", pdev->irq); status = request_threaded_irq(drv_data->irq, - i2s_irq, - i2s_irq_deferred, - IRQF_SHARED, - "i2s ssp", - drv_data); + i2s_irq, + i2s_irq_deferred, + IRQF_SHARED, + "i2s ssp", + drv_data); +#else /* __MRFL_SPECIFIC_TMP__ */ + /* FIXME: remove when threaded irq will work on MRFL kernel */ + dev_info(&(pdev->dev), "attaching to IRQ: %04x\n", pdev->irq); + + status = request_irq(drv_data->irq, + i2s_irq, + IRQF_SHARED, + "i2s ssp", + drv_data); +#endif /* __MRFL_SPECIFIC_TMP__ */ if (status < 0) { dev_err(&pdev->dev, "can not get IRQ. status err=%d\n", status); @@ -2710,6 +2852,15 @@ static int __init intel_mid_i2s_init(void) { clear_bit(MODEM_FND, &modem_found_and_i2s_setup_ok); +#ifdef __MRFL_SPECIFIC_TMP__ + /* FIXME: use of MRFL_LPE_SHIM_REG_BASE_ADDRESS should be + * avoided and replaced by a call to SST driver that will + * take care to access LPE Shim registers */ + + lpeshim_base_address = ioremap(MRFL_LPE_SHIM_REG_BASE_ADDRESS, + MRFL_LPE_SHIM_REG_SIZE); +#endif /* __MRFL_SPECIFIC_TMP__ */ + return pci_register_driver(&intel_mid_i2s_driver); } @@ -2721,6 +2872,3 @@ static void __exit intel_mid_i2s_exit(void) module_init_async(intel_mid_i2s_init); module_exit(intel_mid_i2s_exit); - - - diff --git a/sound/pci/intel_mid_i2s/intel_mid_i2s.h b/sound/pci/intel_mid_i2s/intel_mid_i2s.h index 485d224..b3ce67d 100644 --- a/sound/pci/intel_mid_i2s/intel_mid_i2s.h +++ b/sound/pci/intel_mid_i2s/intel_mid_i2s.h @@ -22,6 +22,13 @@ #include #include +#ifdef CONFIG_X86_MRFLD +#define __MRFL_SPECIFIC__ + +/* For temporary MRFL work-around */ +/* To Be Removed when fixed */ +#define __MRFL_SPECIFIC_TMP__ +#endif /* CONFIG_X86_MRFLD */ /* * Main Defines @@ -42,6 +49,25 @@ #define CLV_SSP1_DEVICE_ID 0x08E8 #define CLV_LPE_DMA_DEVICE_ID 0x08F0 +/* Merrifield */ +#define MRFL_SSP_DEVICE_ID 0x1193 +#define MRFL_LPE_DMA_DEVICE_ID 0x119B + +#ifdef __MRFL_SPECIFIC_TMP__ +/* FIXME: use of MRFL_SSPx_REG_BASE_ADDRESS should be + * avoided by PCI table reorganization which allow to + * determine SSP # from PCI info */ +#define MRFL_SSP0_REG_BASE_ADDRESS (0xff2a0000) +#define MRFL_SSP1_REG_BASE_ADDRESS (0xff2a1000) +#define MRFL_SSP2_REG_BASE_ADDRESS (0xff2a2000) + +/* FIXME: use of fixed addresses should be + * replaced by a call to SST driver that will + * take care to access LPE Shim registers */ +#define MRFL_LPE_SHIM_REG_BASE_ADDRESS (0xff340000) +#define MRFL_LPE_SHIM_REG_SIZE (0xE8) +#endif /* __MRFL_SPECIFIC_TMP__ */ + /* SSP PCI device definitions */ #define MRST_SSP_BAR 0 #define MRST_LPE_BAR 1 @@ -113,6 +139,9 @@ DEFINE_REG(LPE_IPCD, 0x40) /* IPC SST-IA */ DEFINE_REG(LPE_ISRD, 0x20) /* dummy register for*/ /* shim workaround */ DEFINE_REG(LPE_CLKCTL, 0x78) +#ifdef __MRFL_SPECIFIC__ +DEFINE_REG(LPE_CHICKEN_BITS, 0x88) +#endif /* __MRFL_SPECIFIC__ */ /* LPE_ISRX fields definitions */ DEFINE_FIELD(LPE_ISRX, IAPIS_SSP0, 0x01, 3); @@ -136,6 +165,24 @@ DEFINE_REG(SSRSA, 0x34) /* SSP Rx Timeslot Active */ DEFINE_REG(SSTSS, 0x38) DEFINE_REG(SSACD, 0x3C) +#ifdef __MRFL_SPECIFIC__ +DEFINE_REG(SSCR2, 0x40) +DEFINE_REG(SSFS, 0x44) +DEFINE_REG(FRAME_CNT0, 0x48) +DEFINE_REG(FRAME_CNT1, 0x4C) +DEFINE_REG(FRAME_CNT2, 0x50) +DEFINE_REG(FRAME_CNT3, 0x54) +DEFINE_REG(FRAME_CNT4, 0x58) +DEFINE_REG(FRAME_CNT5, 0x5C) +DEFINE_REG(FRAME_CNT6, 0x60) +DEFINE_REG(FRAME_CNT7, 0x64) +DEFINE_REG(SFIFOL, 0x68) +DEFINE_REG(SFIFOTT, 0x6C) +DEFINE_REG(SSCR3, 0x70) +DEFINE_REG(SSCR4, 0x74) +DEFINE_REG(SSCR5, 0x78) +#endif /* __MRFL_SPECIFIC__ */ + /* SSP SSCR0 fields definitions */ DEFINE_FIELD(SSCR0, DSS, 0x0F, 0); /* Data Size Select [4..16] */ DEFINE_FIELD(SSCR0, FRF, 0x03, 4); /* Frame Format */ @@ -222,6 +269,16 @@ DEFINE_FIELD(SSSR, BSY, 0x1, 4); /* SSP Busy */ DEFINE_FIELD(SSSR, RNE, 0x1, 3); /* Receive FIFO not empty */ DEFINE_FIELD(SSSR, TNF, 0x1, 2); /* Transmit FIFO not Full */ +#ifdef __MRFL_SPECIFIC__ +/* SSP SFIFOL fields definitions */ +DEFINE_FIELD(SFIFOL, RFL, 0xFFFF, 16) /* Receive FIFO Level */ +DEFINE_FIELD(SFIFOL, TFL, 0xFFFF, 0) /* Transmit FIFO Level */ + +/* SSP SFIFOL fields definitions */ +DEFINE_FIELD(SFIFOTT, RFT, 0xFFFF, 16) /* Receive FIFO Trigger Threshold */ +DEFINE_FIELD(SFIFOTT, TFT, 0xFFFF, 0) /* Transmit FIFO Trigger Threshold */ +#endif /* __MRFL_SPECIFIC__ */ + /* * list of differents types of SSP, value depends of adid entry of -- 2.7.4