diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile index 2a6fd7420c..07b590156c 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -17,4 +17,5 @@ obj-$(CONFIG_SOUND_MAX98090) += max98090.o maxim_codec.o obj-$(CONFIG_SOUND_MAX98095) += max98095.o maxim_codec.o obj-$(CONFIG_SOUND_INTEL_HDA) += hda_codec.o obj-$(CONFIG_SOUND_I8254) += i8254_beep.o +obj-$(CONFIG_INTEL_BROADWELL) += broadwell_i2s.o obj-$(CONFIG_SOUND_IVYBRIDGE) += ivybridge_sound.o diff --git a/drivers/sound/broadwell_i2s.c b/drivers/sound/broadwell_i2s.c new file mode 100644 index 0000000000..998792b239 --- /dev/null +++ b/drivers/sound/broadwell_i2s.c @@ -0,0 +1,306 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Intel Broadwell I2S driver + * + * Copyright 2019 Google LLC + * + * Modified from dc i2s/broadwell/broadwell.c + */ + +#define LOG_CATEGORY UCLASS_I2S + +#include +#include +#include +#include +#include "broadwell_i2s.h" + +enum { + BDW_SHIM_START_ADDRESS = 0xfb000, + BDW_SSP0_START_ADDRESS = 0xfc000, + BDW_SSP1_START_ADDRESS = 0xfd000, +}; + +struct broadwell_i2s_priv { + enum frame_sync_rel_timing_t rel_timing; + enum frame_sync_pol_t sfrm_polarity; + enum end_transfer_state_t end_transfer_state; + enum clock_mode_t sclk_mode; + uint sclk_dummy_stop; /* 0-31 */ + uint sclk_frame_width; /* 1-38 */ + struct i2s_shim_regs *shim; + struct broadwell_i2s_regs *regs; +}; + +static void init_shim_csr(struct broadwell_i2s_priv *priv) +{ + /* + * Select SSP clock + * Turn off low power clock + * Set PIO mode + * Stall DSP core + */ + clrsetbits_le32(&priv->shim->csr, + SHIM_CS_S0IOCS | SHIM_CS_LPCS | SHIM_CS_DCS_MASK, + SHIM_CS_S1IOCS | SHIM_CS_SBCS_SSP1_24MHZ | + SHIM_CS_SBCS_SSP0_24MHZ | SHIM_CS_SDPM_PIO_SSP1 | + SHIM_CS_SDPM_PIO_SSP0 | SHIM_CS_STALL | + SHIM_CS_DCS_DSP32_AF32); +} + +static void init_shim_clkctl(struct i2s_uc_priv *uc_priv, + struct broadwell_i2s_priv *priv) +{ + u32 clkctl = readl(&priv->shim->clkctl); + + /* Set 24Mhz mclk, prevent local clock gating, enable SSP0 clock */ + clkctl &= SHIM_CLKCTL_RESERVED; + clkctl |= SHIM_CLKCTL_MCLK_24MHZ | SHIM_CLKCTL_DCPLCG; + + /* Enable requested SSP interface */ + if (uc_priv->id) + clkctl |= SHIM_CLKCTL_SCOE_SSP1 | SHIM_CLKCTL_SFLCGB_SSP1_CGD; + else + clkctl |= SHIM_CLKCTL_SCOE_SSP0 | SHIM_CLKCTL_SFLCGB_SSP0_CGD; + + writel(clkctl, &priv->shim->clkctl); +} + +static void init_sscr0(struct i2s_uc_priv *uc_priv, + struct broadwell_i2s_priv *priv) +{ + u32 sscr0; + uint scale; + + /* Set data size based on BPS */ + if (uc_priv->bitspersample > 16) + sscr0 = (uc_priv->bitspersample - 16 - 1) << SSP_SSC0_DSS_SHIFT + | SSP_SSC0_EDSS; + else + sscr0 = (uc_priv->bitspersample - 1) << SSP_SSC0_DSS_SHIFT; + + /* Set network mode, Stereo PSP frame format */ + sscr0 |= SSP_SSC0_MODE_NETWORK | + SSP_SSC0_FRDC_STEREO | + SSP_SSC0_FRF_PSP | + SSP_SSC0_TIM | + SSP_SSC0_RIM | + SSP_SSC0_ECS_PCH | + SSP_SSC0_NCS_PCH | + SSP_SSC0_ACS_PCH; + + /* Scale 24MHz MCLK */ + scale = uc_priv->audio_pll_clk / uc_priv->samplingrate / uc_priv->bfs; + sscr0 |= scale << SSP_SSC0_SCR_SHIFT; + + writel(sscr0, &priv->regs->sscr0); +} + +static void init_sscr1(struct broadwell_i2s_priv *priv) +{ + u32 sscr1 = readl(&priv->regs->sscr1); + + sscr1 &= SSP_SSC1_RESERVED; + + /* Set as I2S master */ + sscr1 |= SSP_SSC1_SCLKDIR_MASTER | SSP_SSC1_SCLKDIR_MASTER; + + /* Enable TXD tristate behavior for PCH */ + sscr1 |= SSP_SSC1_TTELP | SSP_SSC1_TTE; + + /* Disable DMA Tx/Rx service request */ + sscr1 |= SSP_SSC1_TSRE | SSP_SSC1_RSRE; + + /* Clock on during transfer */ + sscr1 |= SSP_SSC1_SCFR; + + /* Set FIFO thresholds */ + sscr1 |= SSP_FIFO_SIZE << SSP_SSC1_RFT_SHIFT; + sscr1 |= SSP_FIFO_SIZE << SSP_SSC1_TFT_SHIFT; + + /* Disable interrupts */ + sscr1 &= ~(SSP_SSC1_EBCEI | SSP_SSC1_TINTE | SSP_SSC1_PINTE); + sscr1 &= ~(SSP_SSC1_LBM | SSP_SSC1_RWOT); + + writel(sscr1, &priv->regs->sscr1); +} + +static void init_sspsp(struct broadwell_i2s_priv *priv) +{ + u32 sspsp = readl(&priv->regs->sspsp); + + sspsp &= SSP_PSP_RESERVED; + sspsp |= priv->sclk_mode << SSP_PSP_SCMODE_SHIFT; + sspsp |= (priv->sclk_dummy_stop << SSP_PSP_DMYSTOP_SHIFT) & + SSP_PSP_DMYSTOP_MASK; + sspsp |= (priv->sclk_dummy_stop >> 2 << SSP_PSP_EDYMSTOP_SHIFT) & + SSP_PSP_EDMYSTOP_MASK; + sspsp |= priv->sclk_frame_width << SSP_PSP_SFRMWDTH_SHIFT; + + /* Frame Sync Relative Timing */ + if (priv->rel_timing == NEXT_FRMS_AFTER_END_OF_T4) + sspsp |= SSP_PSP_FSRT; + else + sspsp &= ~SSP_PSP_FSRT; + + /* Serial Frame Polarity */ + if (priv->sfrm_polarity == SSP_FRMS_ACTIVE_HIGH) + sspsp |= SSP_PSP_SFRMP; + else + sspsp &= ~SSP_PSP_SFRMP; + + /* End Data Transfer State */ + if (priv->end_transfer_state == SSP_END_TRANSFER_STATE_LOW) + sspsp &= ~SSP_PSP_ETDS; + else + sspsp |= SSP_PSP_ETDS; + + writel(sspsp, &priv->regs->sspsp); +} + +static void init_ssp_time_slot(struct broadwell_i2s_priv *priv) +{ + writel(3, &priv->regs->sstsa); + writel(3, &priv->regs->ssrsa); +} + +static int bdw_i2s_init(struct udevice *dev) +{ + struct i2s_uc_priv *uc_priv = dev_get_uclass_priv(dev); + struct broadwell_i2s_priv *priv = dev_get_priv(dev); + + init_shim_csr(priv); + init_shim_clkctl(uc_priv, priv); + init_sscr0(uc_priv, priv); + init_sscr1(priv); + init_sspsp(priv); + init_ssp_time_slot(priv); + + return 0; +} + +static void bdw_i2s_enable(struct broadwell_i2s_priv *priv) +{ + setbits_le32(&priv->regs->sscr0, SSP_SSC0_SSE); + setbits_le32(&priv->regs->sstsa, SSP_SSTSA_EN); +} + +static void bdw_i2s_disable(struct broadwell_i2s_priv *priv) +{ + clrbits_le32(&priv->regs->sstsa, SSP_SSTSA_EN); + clrbits_le32(&priv->regs->sstsa, SSP_SSTSA_EN); +} + +static int broadwell_i2s_tx_data(struct udevice *dev, void *data, + uint data_size) +{ + struct broadwell_i2s_priv *priv = dev_get_priv(dev); + u32 *ptr = data; + + log_debug("data=%p, data_size=%x\n", data, data_size); + if (data_size < SSP_FIFO_SIZE) { + log_err("Invalid I2S data size\n"); + return -ENODATA; + } + + /* Enable I2S interface */ + bdw_i2s_enable(priv); + + /* Transfer data */ + while (data_size > 0) { + ulong start = timer_get_us() + 100000; + + /* Write data if transmit FIFO has room */ + if (readl(&priv->regs->sssr) & SSP_SSS_TNF) { + writel(*ptr++, &priv->regs->ssdr); + data_size -= sizeof(*ptr); + } else { + if ((long)(timer_get_us() - start) > 0) { + /* Disable I2S interface */ + bdw_i2s_disable(priv); + log_debug("I2S Transfer Timeout\n"); + return -ETIMEDOUT; + } + } + } + + /* Disable I2S interface */ + bdw_i2s_disable(priv); + log_debug("done\n"); + + return 0; +} + +static int broadwell_i2s_probe(struct udevice *dev) +{ + struct i2s_uc_priv *uc_priv = dev_get_uclass_priv(dev); + struct broadwell_i2s_priv *priv = dev_get_priv(dev); + struct udevice *adsp = dev_get_parent(dev); + u32 bar0, offset; + int ret; + + bar0 = dm_pci_read_bar32(adsp, 0); + if (!bar0) { + log_debug("Cannot read adsp bar0\n"); + return -EINVAL; + } + offset = dev_read_addr_index(dev, 0); + if (offset == FDT_ADDR_T_NONE) { + log_debug("Cannot read address index 0\n"); + return -EINVAL; + } + uc_priv->base_address = bar0 + offset; + + /* + * Hard-code these values. If other settings are required we can add + * this to the device tree. + */ + uc_priv->rfs = 64; + uc_priv->bfs = 32; + uc_priv->audio_pll_clk = 24 * 1000 * 1000; + uc_priv->samplingrate = 48000; + uc_priv->bitspersample = 16; + uc_priv->channels = 2; + uc_priv->id = 0; + + priv->shim = (struct i2s_shim_regs *)uc_priv->base_address; + priv->sfrm_polarity = SSP_FRMS_ACTIVE_LOW; + priv->end_transfer_state = SSP_END_TRANSFER_STATE_LOW; + priv->sclk_mode = SCLK_MODE_DDF_DSR_ISL; + priv->rel_timing = NEXT_FRMS_WITH_LSB_PREVIOUS_FRM; + priv->sclk_dummy_stop = 0; + priv->sclk_frame_width = 31; + + offset = dev_read_addr_index(dev, 1 + uc_priv->id); + if (offset == FDT_ADDR_T_NONE) { + log_debug("Cannot read address index %d\n", 1 + uc_priv->id); + return -EINVAL; + } + log_debug("bar0=%x, uc_priv->base_address=%x, offset=%x\n", bar0, + uc_priv->base_address, offset); + priv->regs = (struct broadwell_i2s_regs *)(bar0 + offset); + + ret = bdw_i2s_init(dev); + if (ret) + return ret; + + return 0; +} + +static const struct i2s_ops broadwell_i2s_ops = { + .tx_data = broadwell_i2s_tx_data, +}; + +static const struct udevice_id broadwell_i2s_ids[] = { + { .compatible = "intel,broadwell-i2s" }, + { } +}; + +U_BOOT_DRIVER(broadwell_i2s) = { + .name = "broadwell_i2s", + .id = UCLASS_I2S, + .of_match = broadwell_i2s_ids, + .probe = broadwell_i2s_probe, + .ops = &broadwell_i2s_ops, + .priv_auto_alloc_size = sizeof(struct broadwell_i2s_priv), +}; diff --git a/drivers/sound/broadwell_i2s.h b/drivers/sound/broadwell_i2s.h new file mode 100644 index 0000000000..ba87abfc6a --- /dev/null +++ b/drivers/sound/broadwell_i2s.h @@ -0,0 +1,301 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Intel Broadwell I2S driver + * + * Copyright 2019 Google LLC + * + * Modified from dc i2s/broadwell/broadwell.h + */ + +#ifndef __BROADWELL_I2S_H__ +#define __BROADWELL_I2S_H__ + +enum { + SSP_FIFO_SIZE = 7, +}; + +enum frame_sync_rel_timing_t { + NEXT_FRMS_AFTER_END_OF_T4 = 0, + NEXT_FRMS_WITH_LSB_PREVIOUS_FRM, +}; + +enum frame_sync_pol_t { + SSP_FRMS_ACTIVE_LOW = 0, + SSP_FRMS_ACTIVE_HIGH, +}; + +enum end_transfer_state_t { + SSP_END_TRANSFER_STATE_LOW = 0, + SSP_END_TRANSFER_STATE_PEVIOUS_BIT, +}; + +enum clock_mode_t { + /* Data driven (falling), data sampled (rising), idle state (low) */ + SCLK_MODE_DDF_DSR_ISL, + /* Data driven (rising), data sampled (falling), idle state (low) */ + SCLK_MODE_DDR_DSF_ISL, + /* Data driven (rising), data sampled (falling), idle state (high) */ + SCLK_MODE_DDR_DSF_ISH, + /* Data driven (falling), data sampled (rising), idle state (high) */ + SCLK_MODE_DDF_DSR_ISH, +}; + +struct i2s_shim_regs { + u32 csr; /* 0x00 */ + u32 reserved0[29]; /* 0x14 - 0x77 */ + u32 clkctl; /* 0x78 */ + u32 reserved1; /* 0x7c */ + u32 cs2; /* 0x80 */ +}; + +struct broadwell_i2s_regs { + u32 sscr0; /* 0x00 */ + u32 sscr1; /* 0x04 */ + u32 sssr; /* 0x08 */ + u32 ssitr; /* 0x0c */ + u32 ssdr; /* 0x10 */ + u32 reserved0[5]; /* 0x14 - 0x27 */ + u32 ssto; /* 0x28 */ + u32 sspsp; /* 0x2c */ + u32 sstsa; /* 0x30 */ + u32 ssrsa; /* 0x34 */ + u32 sstss; /* 0x38 */ + u32 sscr2; /* 0x40 */ + u32 sspsp2; /* 0x44 */ +}; + +/* SHIM Configuration & Status */ +enum { + /* Low Power Clock Select */ + SHIM_CS_LPCS = 1 << 31, + /* SSP Force Clock Running */ + SHIM_CS_SFCR_SSP1 = 1 << 28, + SHIM_CS_SFCR_SSP0 = 1 << 27, + /* SSP1 IO Clock Select */ + SHIM_CS_S1IOCS = 1 << 23, + /* SSP0 IO Clock Select */ + SHIM_CS_S0IOCS = 1 << 21, + /* Parity Check Enable */ + SHIM_CS_PCE = 1 << 15, + /* SSP DMA or PIO Mode */ + SHIM_CS_SDPM_PIO_SSP1 = 1 << 12, + SHIM_CS_SDPM_DMA_SSP1 = 0 << 12, + SHIM_CS_SDPM_PIO_SSP0 = 1 << 11, + SHIM_CS_SDPM_DMA_SSP0 = 0 << 11, + /* Run / Stall */ + SHIM_CS_STALL = 1 << 10, + /* DSP Clock Select */ + SHIM_CS_DCS_DSP320_AF80 = 0 << 4, + SHIM_CS_DCS_DSP160_AF80 = 1 << 4, + SHIM_CS_DCS_DSP80_AF80 = 2 << 4, + SHIM_CS_DCS_DSP320_AF160 = 4 << 4, + SHIM_CS_DCS_DSP160_AF160 = 5 << 4, + SHIM_CS_DCS_DSP32_AF32 = 6 << 4, + SHIM_CS_DCS_MASK = 7 << 4, + /* SSP Base Clock Select */ + SHIM_CS_SBCS_SSP0_24MHZ = 1 << 3, + SHIM_CS_SBCS_SSP0_32MHZ = 0 << 3, + SHIM_CS_SBCS_SSP1_24MHZ = 1 << 2, + SHIM_CS_SBCS_SSP1_32MHZ = 0 << 2, + /* DSP Core Reset */ + SHIM_CS_RST = 1 << 1, +}; + +/* SHIM Clock Control */ +enum { + /* Clock Frequency Change In Progress */ + SHIM_CLKCTL_CFCIP = 1 << 31, + /* SSP MCLK Output Select */ + SHIM_CLKCTL_MCLK_MASK = 0x3, + SHIM_CLKCTL_MCLK_SHIFT = 24, + SHIM_CLKCTL_MCLK_DISABLED = 0 << 24, + SHIM_CLKCTL_MCLK_6MHZ = 1 << 24, + SHIM_CLKCTL_MCLK_12MHZ = 2 << 24, + SHIM_CLKCTL_MCLK_24MHZ = 3 << 24, + /* DSP Core Prevent Local Clock Gating */ + SHIM_CLKCTL_DCPLCG = 1 << 18, + /* SSP Clock Output Enable */ + SHIM_CLKCTL_SCOE_SSP1 = 1 << 17, + SHIM_CLKCTL_SCOE_SSP0 = 1 << 16, + /* DMA Engine Force Local Clock Gating */ + SHIM_CLKCTL_DEFLCGB_DMA1_CGE = 0 << 6, + SHIM_CLKCTL_DEFLCGB_DMA1_CGD = 1 << 6, + SHIM_CLKCTL_DEFLCGB_DMA0_CGE = 0 << 5, + SHIM_CLKCTL_DEFLCGB_DMA0_CGD = 1 << 5, + /* SSP Force Local Clock Gating */ + SHIM_CLKCTL_SFLCGB_SSP1_CGE = 0 << 1, + SHIM_CLKCTL_SFLCGB_SSP1_CGD = 1 << 1, + SHIM_CLKCTL_SFLCGB_SSP0_CGE = 0 << 0, + SHIM_CLKCTL_SFLCGB_SSP0_CGD = 1 << 0, + + /* Reserved bits: 30:26, 23:19, 15:7, 4:2 */ + SHIM_CLKCTL_RESERVED = 0x1f << 26 | 0x1f << 19 | 0x1ff << 7 | 0x7 << 2, +}; + +/* SSP Status */ +enum { + /* Bit Count Error */ + SSP_SSS_BCE = 1 << 23, + /* Clock Sync Statu s*/ + SSP_SSS_CSS = 1 << 22, + /* Transmit FIFO Underrun */ + SSP_SSS_TUR = 1 << 21, + /* End Of Chain */ + SSP_SSS_EOC = 1 << 20, + /* Receiver Time-out Interrupt */ + SSP_SSS_TINT = 1 << 19, + /* Peripheral Trailing Byte Interrupt */ + SSP_SSS_PINT = 1 << 18, + /* Received FIFO Level */ + SSP_RFL_MASK = 0xf, + SSP_RFL_SHIFT = 12, + /* Transmit FIFO Level */ + SSP_TFL_MASK = 0xf, + SSP_TFL_SHIFT = 8, + /* Receive FIFO Overrun */ + SSP_SSS_ROR = 1 << 7, + /* Receive FIFO Service Request */ + SSP_SSS_RFS = 1 << 6, + /* Transmit FIFO Service Request */ + SSP_SSS_TFS = 1 << 5, + /* SSP Busy */ + SSP_SSS_BSY = 1 << 4, + /* Receive FIFO Not Empty */ + SSP_SSS_RNE = 1 << 3, + /* Transmit FIFO Not Full */ + SSP_SSS_TNF = 1 << 2, +}; + +/* SSP Control 0 */ +enum { + /* Mode */ + SSP_SSC0_MODE_NORMAL = 0 << 31, + SSP_SSC0_MODE_NETWORK = 1 << 31, + /* Audio Clock Select */ + SSP_SSC0_ACS_PCH = 0 << 30, + /* Frame Rate Divider Control (0-7) */ + SSP_SSC0_FRDC_MASK = 0x7, + SSP_SSC0_FRDC_SHIFT = 24, + SSP_SSC0_FRDC_STEREO = 1 << 24, + /* Transmit FIFO Underrun Interrupt Mask */ + SSP_SSC0_TIM = 1 << 23, + /* Receive FIFO Underrun Interrupt Mask */ + SSP_SSC0_RIM = 1 << 22, + /* Network Clock Select */ + SSP_SSC0_NCS_PCH = 0 << 21, + /* Extended Data Size Select */ + SSP_SSC0_EDSS = 1 << 20, + /* Serial Clock Rate (0-4095) */ + SSP_SSC0_SCR_SHIFT = 8, + SSP_SSC0_SCR_MASK = 0xfff << SSP_SSC0_SCR_SHIFT, + /* Synchronous Serial Port Enable */ + SSP_SSC0_SSE = 1 << 7, + /* External Clock Select */ + SSP_SSC0_ECS_PCH = 0 << 6, + /* Frame Format */ + SSP_SSC0_FRF_MOTOROLA_SPI = 0 << 4, + SSP_SSC0_FRF_TI_SSP = 1 << 4, + SSP_SSC0_FRF_NS_MICROWIRE = 2 << 4, + SSP_SSC0_FRF_PSP = 3 << 4, + /* Data Size Select */ + SSP_SSC0_DSS_SHIFT = 0, + SSP_SSC0_DSS_MASK = 0xf << SSP_SSC0_DSS_SHIFT, +}; + +/* SSP Control 1 */ +enum { + /* TXD Tristate Enable on Last Phase */ + SSP_SSC1_TTELP = 1 << 31, + /* TXD Tristate Enable */ + SSP_SSC1_TTE = 1 << 30, + /* Enable Bit Count Error Interrupt */ + SSP_SSC1_EBCEI = 1 << 29, + /* Slave Clock Running */ + SSP_SSC1_SCFR = 1 << 28, + /* Enable Clock Request A */ + SSP_SSC1_ECRA = 1 << 27, + /* Enable Clock Request B */ + SSP_SSC1_ECRB = 1 << 26, + /* SSPCLK Direction */ + SSP_SSC1_SCLKDIR_SLAVE = 1 << 25, + SSP_SSC1_SCLKDIR_MASTER = 0 << 25, + /* SSPFRM Direction */ + SSP_SSC1_SFRMDIR_SLAVE = 1 << 24, + SSP_SSC1_SFRMDIR_MASTER = 0 << 24, + /* Receive without Transmit */ + SSP_SSC1_RWOT = 1 << 23, + /* Trailing Byte */ + SSP_SSC1_TRAIL = 1 << 22, + /* DMA Tx Service Request Enable */ + SSP_SSC1_TSRE = 1 << 21, + /* DMA Rx Service Request Enable */ + SSP_SSC1_RSRE = 1 << 20, + /* Receiver Timeout Interrupt Enable */ + SSP_SSC1_TINTE = 1 << 19, + /* Periph. Trailing Byte Int. Enable */ + SSP_SSC1_PINTE = 1 << 18, + /* Invert Frame Signal */ + SSP_SSC1_IFS = 1 << 16, + /* Select FIFO for EFWR: test mode */ + SSP_SSC1_STRF = 1 << 15, + /* Enable FIFO Write/Read: test mode */ + SSP_SSC1_EFWR = 1 << 14, + /* Receive FIFO Trigger Threshold */ + SSP_SSC1_RFT_SHIFT = 10, + SSP_SSC1_RFT_MASK = 0xf << SSP_SSC1_RFT_SHIFT, + /* Transmit FIFO Trigger Threshold */ + SSP_SSC1_TFT_SHIFT = 6, + SSP_SSC1_TFT_MASK = 0xf << SSP_SSC1_TFT_SHIFT, + /* Microwire Transmit Data Size */ + SSP_SSC1_MWDS = 1 << 5, + /* Motorola SPI SSPSCLK Phase Setting*/ + SSP_SSC1_SPH = 1 << 4, + /* Motorola SPI SSPSCLK Polarity */ + SSP_SSC1_SPO = 1 << 3, + /* Loopback mode: test mode */ + SSP_SSC1_LBM = 1 << 2, + /* Transmit FIFO Interrupt Enable */ + SSP_SSC1_TIE = 1 << 1, + /* Receive FIFO Interrupt Enable */ + SSP_SSC1_RIE = 1 << 0, + + SSP_SSC1_RESERVED = 17 << 1, +}; + +/* SSP Programmable Serial Protocol */ +enum { + /* Extended Dummy Stop (0-31) */ + SSP_PSP_EDYMSTOP_SHIFT = 26, + SSP_PSP_EDMYSTOP_MASK = 0x7 << SSP_PSP_EDYMSTOP_SHIFT, + /* Frame Sync Relative Timing */ + SSP_PSP_FSRT = 1 << 25, + /* Dummy Stop low bits */ + SSP_PSP_DMYSTOP_SHIFT = 23, + SSP_PSP_DMYSTOP_MASK = 0x3 << SSP_PSP_DMYSTOP_SHIFT, + /* Serial Frame Width */ + SSP_PSP_SFRMWDTH_SHIFT = 16, + SSP_PSP_SFRMWDTH_MASK = 0x3f << SSP_PSP_SFRMWDTH_SHIFT, + /* Serial Frame Delay */ + SSP_PSP_SFRMDLY_MASK = 0x7f, + SSP_PSP_SFRMDLY_SHIFT = 9, + /* Start Delay */ + SSP_PSP_STRTDLY_MASK = 0x7, + SSP_PSP_STRTDLY_SHIFT = 4, + /* End of Transfer Data State */ + SSP_PSP_ETDS = 1 << 3, + /* Serial Frame Polarity */ + SSP_PSP_SFRMP = 1 << 2, + /* Serial Clock Mode */ + SSP_PSP_SCMODE_SHIFT = 0, + SSP_PSP_SCMODE_MASK = 0x3 << SSP_PSP_SCMODE_SHIFT, + + SSP_PSP_RESERVED = 1 << 22, +}; + +/* SSP TX Time Slot Active */ +enum { + SSP_SSTSA_EN = 1 << 8, + SSP_SSTSA_MASK = 0xff, +}; + +#endif /* __BROADWELL_I2S_H__ */