static void tda998x_audio_mute(struct tda998x_priv *priv, bool on) { if (on) { reg_set(priv, REG_SOFTRESET, SOFTRESET_AUDIO); reg_clear(priv, REG_SOFTRESET, SOFTRESET_AUDIO); reg_set(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO); } else { reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO); } }
static int tda998x_connector_get_modes(struct drm_connector *connector) { struct tda998x_priv *priv = conn_to_tda998x_priv(connector); struct edid *edid; int n; /* * If we get killed while waiting for the HPD timeout, return * no modes found: we are not in a restartable path, so we * can't handle signals gracefully. */ if (tda998x_edid_delay_wait(priv)) return 0; if (priv->rev == TDA19988) reg_clear(priv, REG_TX4, TX4_PD_RAM); edid = drm_do_get_edid(connector, read_edid_block, priv); if (priv->rev == TDA19988) reg_set(priv, REG_TX4, TX4_PD_RAM); if (!edid) { dev_warn(&priv->hdmi->dev, "failed to read EDID\n"); return 0; } drm_mode_connector_update_edid_property(connector, edid); n = drm_add_edid_modes(connector, edid); priv->is_hdmi_sink = drm_detect_hdmi_monitor(edid); kfree(edid); return n; }
static void tda998x_reset(struct tda998x_priv *priv) { /* reset audio and i2c master: */ reg_write(priv, REG_SOFTRESET, SOFTRESET_AUDIO | SOFTRESET_I2C_MASTER); msleep(50); reg_write(priv, REG_SOFTRESET, 0); msleep(50); /* reset transmitter: */ reg_set(priv, REG_MAIN_CNTRL0, MAIN_CNTRL0_SR); reg_clear(priv, REG_MAIN_CNTRL0, MAIN_CNTRL0_SR); /* PLL registers common configuration */ reg_write(priv, REG_PLL_SERIAL_1, 0x00); reg_write(priv, REG_PLL_SERIAL_2, PLL_SERIAL_2_SRL_NOSC(1)); reg_write(priv, REG_PLL_SERIAL_3, 0x00); reg_write(priv, REG_SERIALIZER, 0x00); reg_write(priv, REG_BUFFER_OUT, 0x00); reg_write(priv, REG_PLL_SCG1, 0x00); reg_write(priv, REG_AUDIO_DIV, AUDIO_DIV_SERCLK_8); reg_write(priv, REG_SEL_CLK, SEL_CLK_SEL_CLK1 | SEL_CLK_ENA_SC_CLK); reg_write(priv, REG_PLL_SCGN1, 0xfa); reg_write(priv, REG_PLL_SCGN2, 0x00); reg_write(priv, REG_PLL_SCGR1, 0x5b); reg_write(priv, REG_PLL_SCGR2, 0x00); reg_write(priv, REG_PLL_SCG2, 0x10); /* Write the default value MUX register */ reg_write(priv, REG_MUX_VP_VIP_OUT, 0x24); }
static int tda998x_encoder_get_modes(struct tda998x_priv *priv, struct drm_connector *connector) { struct edid *edid; int n; if (priv->rev == TDA19988) reg_clear(priv, REG_TX4, TX4_PD_RAM); edid = drm_do_get_edid(connector, read_edid_block, priv); if (priv->rev == TDA19988) reg_set(priv, REG_TX4, TX4_PD_RAM); if (!edid) { dev_warn(&priv->hdmi->dev, "failed to read EDID\n"); return 0; } drm_mode_connector_update_edid_property(connector, edid); n = drm_add_edid_modes(connector, edid); priv->is_hdmi_sink = drm_detect_hdmi_monitor(edid); kfree(edid); return n; }
void init_interrupt(void) { //set ICLR to 0, which mean all the interrupt will generat IRQ reg_write(INT_ICLR_ADDR, 0); //cleean ICMR, then only enable the OSTimer 0 interrupt reg_clear(INT_ICMR_ADDR, 0); reg_write(INT_ICMR_ADDR, 1<<INT_OSTMR_0); }
static void tda998x_write_if(struct tda998x_priv *priv, uint8_t bit, uint16_t addr, uint8_t *buf, size_t size) { reg_clear(priv, REG_DIP_IF_FLAGS, bit); reg_write_range(priv, addr, buf, size); reg_set(priv, REG_DIP_IF_FLAGS, bit); }
static void tda998x_destroy(struct tda998x_priv *priv) { /* disable all IRQs and free the IRQ handler */ cec_write(priv, REG_CEC_RXSHPDINTENA, 0); reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD); if (priv->hdmi->irq) { free_irq(priv->hdmi->irq, priv); cancel_delayed_work_sync(&priv->dwork); } i2c_unregister_device(priv->cec); }
void setup_peripheral_device(unsigned *ICMR, unsigned *ICLR, unsigned *OIER){ *ICMR = reg_read(INT_ICMR_ADDR); *ICLR = reg_read(INT_ICLR_ADDR); *OIER = reg_read(OSTMR_OIER_ADDR); reg_write(INT_ICMR_ADDR,INT_ICCR_DIM<<INT_OSTMR_0); reg_write(INT_ICLR_ADDR,0x0); reg_clear(OSTMR_OIER_ADDR,OSTMR_OIER_E0|OSTMR_OIER_E1|OSTMR_OIER_E2|OSTMR_OIER_E3); reg_set(OSTMR_OIER_ADDR,OSTMR_OIER_E0); reg_write(OSTMR_OSMR_ADDR(0),reg_read(OSTMR_OSCR_ADDR)+irq_elapse_count); }
static int mt9v022_init(struct soc_camera_device *icd) { struct i2c_client *client = to_i2c_client(icd->control); struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); struct soc_camera_link *icl = client->dev.platform_data; int ret; if (icl->power) { ret = icl->power(&client->dev, 1); if (ret < 0) { dev_err(icd->vdev->parent, "Platform failed to power-on the camera.\n"); return ret; } } /* * The camera could have been already on, we hard-reset it additionally, * if available. Soft reset is done in video_probe(). */ if (icl->reset) icl->reset(&client->dev); /* Almost the default mode: master, parallel, simultaneous, and an * undocumented bit 0x200, which is present in table 7, but not in 8, * plus snapshot mode to disable scan for now */ mt9v022->chip_control |= 0x10; ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control); if (!ret) ret = reg_write(client, MT9V022_READ_MODE, 0x300); /* All defaults */ if (!ret) /* AEC, AGC on */ ret = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x3); if (!ret) ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480); if (!ret) /* default - auto */ ret = reg_clear(client, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1); if (!ret) ret = reg_write(client, MT9V022_DIGITAL_TEST_PATTERN, 0); return ret; }
static void tda998x_write_if(struct tda998x_priv *priv, u8 bit, u16 addr, union hdmi_infoframe *frame) { u8 buf[32]; ssize_t len; len = hdmi_infoframe_pack(frame, buf, sizeof(buf)); if (len < 0) { dev_err(&priv->hdmi->dev, "hdmi_infoframe_pack() type=0x%02x failed: %zd\n", frame->any.type, len); return; } reg_clear(priv, REG_DIP_IF_FLAGS, bit); reg_write_range(priv, addr, buf, len); reg_set(priv, REG_DIP_IF_FLAGS, bit); }
static void tda998x_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct tda998x_priv *priv = enc_to_tda998x_priv(encoder); u16 ref_pix, ref_line, n_pix, n_line; u16 hs_pix_s, hs_pix_e; u16 vs1_pix_s, vs1_pix_e, vs1_line_s, vs1_line_e; u16 vs2_pix_s, vs2_pix_e, vs2_line_s, vs2_line_e; u16 vwin1_line_s, vwin1_line_e; u16 vwin2_line_s, vwin2_line_e; u16 de_pix_s, de_pix_e; u8 reg, div, rep; /* * Internally TDA998x is using ITU-R BT.656 style sync but * we get VESA style sync. TDA998x is using a reference pixel * relative to ITU to sync to the input frame and for output * sync generation. Currently, we are using reference detection * from HS/VS, i.e. REFPIX/REFLINE denote frame start sync point * which is position of rising VS with coincident rising HS. * * Now there is some issues to take care of: * - HDMI data islands require sync-before-active * - TDA998x register values must be > 0 to be enabled * - REFLINE needs an additional offset of +1 * - REFPIX needs an addtional offset of +1 for UYUV and +3 for RGB * * So we add +1 to all horizontal and vertical register values, * plus an additional +3 for REFPIX as we are using RGB input only. */ n_pix = mode->htotal; n_line = mode->vtotal; hs_pix_e = mode->hsync_end - mode->hdisplay; hs_pix_s = mode->hsync_start - mode->hdisplay; de_pix_e = mode->htotal; de_pix_s = mode->htotal - mode->hdisplay; ref_pix = 3 + hs_pix_s; /* * Attached LCD controllers may generate broken sync. Allow * those to adjust the position of the rising VS edge by adding * HSKEW to ref_pix. */ if (adjusted_mode->flags & DRM_MODE_FLAG_HSKEW) ref_pix += adjusted_mode->hskew; if ((mode->flags & DRM_MODE_FLAG_INTERLACE) == 0) { ref_line = 1 + mode->vsync_start - mode->vdisplay; vwin1_line_s = mode->vtotal - mode->vdisplay - 1; vwin1_line_e = vwin1_line_s + mode->vdisplay; vs1_pix_s = vs1_pix_e = hs_pix_s; vs1_line_s = mode->vsync_start - mode->vdisplay; vs1_line_e = vs1_line_s + mode->vsync_end - mode->vsync_start; vwin2_line_s = vwin2_line_e = 0; vs2_pix_s = vs2_pix_e = 0; vs2_line_s = vs2_line_e = 0; } else { ref_line = 1 + (mode->vsync_start - mode->vdisplay)/2; vwin1_line_s = (mode->vtotal - mode->vdisplay)/2; vwin1_line_e = vwin1_line_s + mode->vdisplay/2; vs1_pix_s = vs1_pix_e = hs_pix_s; vs1_line_s = (mode->vsync_start - mode->vdisplay)/2; vs1_line_e = vs1_line_s + (mode->vsync_end - mode->vsync_start)/2; vwin2_line_s = vwin1_line_s + mode->vtotal/2; vwin2_line_e = vwin2_line_s + mode->vdisplay/2; vs2_pix_s = vs2_pix_e = hs_pix_s + mode->htotal/2; vs2_line_s = vs1_line_s + mode->vtotal/2 ; vs2_line_e = vs2_line_s + (mode->vsync_end - mode->vsync_start)/2; } div = 148500 / mode->clock; if (div != 0) { div--; if (div > 3) div = 3; } /* mute the audio FIFO: */ reg_set(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO); /* set HDMI HDCP mode off: */ reg_write(priv, REG_TBG_CNTRL_1, TBG_CNTRL_1_DWIN_DIS); reg_clear(priv, REG_TX33, TX33_HDMI); reg_write(priv, REG_ENC_CNTRL, ENC_CNTRL_CTL_CODE(0)); /* no pre-filter or interpolator: */ reg_write(priv, REG_HVF_CNTRL_0, HVF_CNTRL_0_PREFIL(0) | HVF_CNTRL_0_INTPOL(0)); reg_write(priv, REG_VIP_CNTRL_5, VIP_CNTRL_5_SP_CNT(0)); reg_write(priv, REG_VIP_CNTRL_4, VIP_CNTRL_4_BLANKIT(0) | VIP_CNTRL_4_BLC(0)); reg_clear(priv, REG_PLL_SERIAL_1, PLL_SERIAL_1_SRL_MAN_IZ); reg_clear(priv, REG_PLL_SERIAL_3, PLL_SERIAL_3_SRL_CCIR | PLL_SERIAL_3_SRL_DE); reg_write(priv, REG_SERIALIZER, 0); reg_write(priv, REG_HVF_CNTRL_1, HVF_CNTRL_1_VQR(0)); /* TODO enable pixel repeat for pixel rates less than 25Msamp/s */ rep = 0; reg_write(priv, REG_RPT_CNTRL, 0); reg_write(priv, REG_SEL_CLK, SEL_CLK_SEL_VRF_CLK(0) | SEL_CLK_SEL_CLK1 | SEL_CLK_ENA_SC_CLK); reg_write(priv, REG_PLL_SERIAL_2, PLL_SERIAL_2_SRL_NOSC(div) | PLL_SERIAL_2_SRL_PR(rep)); /* set color matrix bypass flag: */ reg_write(priv, REG_MAT_CONTRL, MAT_CONTRL_MAT_BP | MAT_CONTRL_MAT_SC(1)); /* set BIAS tmds value: */ reg_write(priv, REG_ANA_GENERAL, 0x09); /* * Sync on rising HSYNC/VSYNC */ reg = VIP_CNTRL_3_SYNC_HS; /* * TDA19988 requires high-active sync at input stage, * so invert low-active sync provided by master encoder here */ if (mode->flags & DRM_MODE_FLAG_NHSYNC) reg |= VIP_CNTRL_3_H_TGL; if (mode->flags & DRM_MODE_FLAG_NVSYNC) reg |= VIP_CNTRL_3_V_TGL; reg_write(priv, REG_VIP_CNTRL_3, reg); reg_write(priv, REG_VIDFORMAT, 0x00); reg_write16(priv, REG_REFPIX_MSB, ref_pix); reg_write16(priv, REG_REFLINE_MSB, ref_line); reg_write16(priv, REG_NPIX_MSB, n_pix); reg_write16(priv, REG_NLINE_MSB, n_line); reg_write16(priv, REG_VS_LINE_STRT_1_MSB, vs1_line_s); reg_write16(priv, REG_VS_PIX_STRT_1_MSB, vs1_pix_s); reg_write16(priv, REG_VS_LINE_END_1_MSB, vs1_line_e); reg_write16(priv, REG_VS_PIX_END_1_MSB, vs1_pix_e); reg_write16(priv, REG_VS_LINE_STRT_2_MSB, vs2_line_s); reg_write16(priv, REG_VS_PIX_STRT_2_MSB, vs2_pix_s); reg_write16(priv, REG_VS_LINE_END_2_MSB, vs2_line_e); reg_write16(priv, REG_VS_PIX_END_2_MSB, vs2_pix_e); reg_write16(priv, REG_HS_PIX_START_MSB, hs_pix_s); reg_write16(priv, REG_HS_PIX_STOP_MSB, hs_pix_e); reg_write16(priv, REG_VWIN_START_1_MSB, vwin1_line_s); reg_write16(priv, REG_VWIN_END_1_MSB, vwin1_line_e); reg_write16(priv, REG_VWIN_START_2_MSB, vwin2_line_s); reg_write16(priv, REG_VWIN_END_2_MSB, vwin2_line_e); reg_write16(priv, REG_DE_START_MSB, de_pix_s); reg_write16(priv, REG_DE_STOP_MSB, de_pix_e); if (priv->rev == TDA19988) { /* let incoming pixels fill the active space (if any) */ reg_write(priv, REG_ENABLE_SPACE, 0x00); } /* * Always generate sync polarity relative to input sync and * revert input stage toggled sync at output stage */ reg = TBG_CNTRL_1_DWIN_DIS | TBG_CNTRL_1_TGL_EN; if (mode->flags & DRM_MODE_FLAG_NHSYNC) reg |= TBG_CNTRL_1_H_TGL; if (mode->flags & DRM_MODE_FLAG_NVSYNC) reg |= TBG_CNTRL_1_V_TGL; reg_write(priv, REG_TBG_CNTRL_1, reg); /* must be last register set: */ reg_write(priv, REG_TBG_CNTRL_0, 0); /* Only setup the info frames if the sink is HDMI */ if (priv->is_hdmi_sink) { /* We need to turn HDMI HDCP stuff on to get audio through */ reg &= ~TBG_CNTRL_1_DWIN_DIS; reg_write(priv, REG_TBG_CNTRL_1, reg); reg_write(priv, REG_ENC_CNTRL, ENC_CNTRL_CTL_CODE(1)); reg_set(priv, REG_TX33, TX33_HDMI); tda998x_write_avi(priv, adjusted_mode); if (priv->params.audio_cfg) tda998x_configure_audio(priv, adjusted_mode, &priv->params); } }
static void tda998x_configure_audio(struct tda998x_priv *priv, struct drm_display_mode *mode, struct tda998x_encoder_params *p) { u8 buf[6], clksel_aip, clksel_fs, cts_n, adiv; u32 n; /* Enable audio ports */ reg_write(priv, REG_ENA_AP, p->audio_cfg); reg_write(priv, REG_ENA_ACLK, p->audio_clk_cfg); /* Set audio input source */ switch (p->audio_format) { case AFMT_SPDIF: reg_write(priv, REG_MUX_AP, MUX_AP_SELECT_SPDIF); clksel_aip = AIP_CLKSEL_AIP_SPDIF; clksel_fs = AIP_CLKSEL_FS_FS64SPDIF; cts_n = CTS_N_M(3) | CTS_N_K(3); break; case AFMT_I2S: reg_write(priv, REG_MUX_AP, MUX_AP_SELECT_I2S); clksel_aip = AIP_CLKSEL_AIP_I2S; clksel_fs = AIP_CLKSEL_FS_ACLK; cts_n = CTS_N_M(3) | CTS_N_K(3); break; default: BUG(); return; } reg_write(priv, REG_AIP_CLKSEL, clksel_aip); reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_LAYOUT | AIP_CNTRL_0_ACR_MAN); /* auto CTS */ reg_write(priv, REG_CTS_N, cts_n); /* * Audio input somehow depends on HDMI line rate which is * related to pixclk. Testing showed that modes with pixclk * >100MHz need a larger divider while <40MHz need the default. * There is no detailed info in the datasheet, so we just * assume 100MHz requires larger divider. */ adiv = AUDIO_DIV_SERCLK_8; if (mode->clock > 100000) adiv++; /* AUDIO_DIV_SERCLK_16 */ /* S/PDIF asks for a larger divider */ if (p->audio_format == AFMT_SPDIF) adiv++; /* AUDIO_DIV_SERCLK_16 or _32 */ reg_write(priv, REG_AUDIO_DIV, adiv); /* * This is the approximate value of N, which happens to be * the recommended values for non-coherent clocks. */ n = 128 * p->audio_sample_rate / 1000; /* Write the CTS and N values */ buf[0] = 0x44; buf[1] = 0x42; buf[2] = 0x01; buf[3] = n; buf[4] = n >> 8; buf[5] = n >> 16; reg_write_range(priv, REG_ACR_CTS_0, buf, 6); /* Set CTS clock reference */ reg_write(priv, REG_AIP_CLKSEL, clksel_aip | clksel_fs); /* Reset CTS generator */ reg_set(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_CTS); reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_CTS); /* Write the channel status */ buf[0] = IEC958_AES0_CON_NOT_COPYRIGHT; buf[1] = 0x00; buf[2] = IEC958_AES3_CON_FS_NOTID; buf[3] = IEC958_AES4_CON_ORIGFS_NOTID | IEC958_AES4_CON_MAX_WORDLEN_24; reg_write_range(priv, REG_CH_STAT_B(0), buf, 4); tda998x_audio_mute(priv, true); msleep(20); tda998x_audio_mute(priv, false); /* Write the audio information packet */ tda998x_write_aif(priv, p); }
void init_interrupt() { /* Clear the last bit of ICLR */ reg_clear(INT_ICLR_ADDR, 1 << INT_OSTMR_0); /* Enable the OS time 0 in the ICMF */ reg_write(INT_ICMR_ADDR, 1 << INT_OSTMR_0); }
static int mt9v022_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) { int data; struct i2c_client *client = to_i2c_client(icd->control); const struct v4l2_queryctrl *qctrl; qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id); if (!qctrl) return -EINVAL; switch (ctrl->id) { case V4L2_CID_VFLIP: if (ctrl->value) data = reg_set(client, MT9V022_READ_MODE, 0x10); else data = reg_clear(client, MT9V022_READ_MODE, 0x10); if (data < 0) return -EIO; break; case V4L2_CID_HFLIP: if (ctrl->value) data = reg_set(client, MT9V022_READ_MODE, 0x20); else data = reg_clear(client, MT9V022_READ_MODE, 0x20); if (data < 0) return -EIO; break; case V4L2_CID_GAIN: /* mt9v022 has minimum == default */ if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) return -EINVAL; else { unsigned long range = qctrl->maximum - qctrl->minimum; /* Datasheet says 16 to 64. autogain only works properly * after setting gain to maximum 14. Larger values * produce "white fly" noise effect. On the whole, * manually setting analog gain does no good. */ unsigned long gain = ((ctrl->value - qctrl->minimum) * 10 + range / 2) / range + 4; if (gain >= 32) gain &= ~1; /* The user wants to set gain manually, hope, she * knows, what she's doing... Switch AGC off. */ if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) return -EIO; dev_info(&icd->dev, "Setting gain from %d to %lu\n", reg_read(client, MT9V022_ANALOG_GAIN), gain); if (reg_write(client, MT9V022_ANALOG_GAIN, gain) < 0) return -EIO; icd->gain = ctrl->value; } break; case V4L2_CID_EXPOSURE: /* mt9v022 has maximum == default */ if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) return -EINVAL; else { unsigned long range = qctrl->maximum - qctrl->minimum; unsigned long shutter = ((ctrl->value - qctrl->minimum) * 479 + range / 2) / range + 1; /* The user wants to set shutter width manually, hope, * she knows, what she's doing... Switch AEC off. */ if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1) < 0) return -EIO; dev_dbg(&icd->dev, "Shutter width from %d to %lu\n", reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH), shutter); if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, shutter) < 0) return -EIO; icd->exposure = ctrl->value; } break; case V4L2_CID_AUTOGAIN: if (ctrl->value) data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2); else data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2); if (data < 0) return -EIO; break; case V4L2_CID_EXPOSURE_AUTO: if (ctrl->value) data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1); else data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1); if (data < 0) return -EIO; break; } return 0; }