/** * isp_set_xclk - Configures the specified cam_xclk to the desired frequency. * @isp: OMAP3 ISP device * @xclk: Desired frequency of the clock in Hz. 0 = stable low, 1 is stable high * @xclksel: XCLK to configure (0 = A, 1 = B). * * Configures the specified MCLK divisor in the ISP timing control register * (TCTRL_CTRL) to generate the desired xclk clock value. * * Divisor = cam_mclk_hz / xclk * * Returns the final frequency that is actually being generated **/ static u32 isp_set_xclk(struct isp_device *isp, u32 xclk, u8 xclksel) { u32 divisor; u32 currentxclk; unsigned long mclk_hz; if (!omap3isp_get(isp)) return 0; mclk_hz = clk_get_rate(isp->clock[ISP_CLK_CAM_MCLK]); if (xclk >= mclk_hz) { divisor = ISPTCTRL_CTRL_DIV_BYPASS; currentxclk = mclk_hz; } else if (xclk >= 2) { divisor = mclk_hz / xclk; if (divisor >= ISPTCTRL_CTRL_DIV_BYPASS) divisor = ISPTCTRL_CTRL_DIV_BYPASS - 1; currentxclk = mclk_hz / divisor; } else { divisor = xclk; currentxclk = 0; } switch (xclksel) { case ISP_XCLK_A: isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL, ISPTCTRL_CTRL_DIVA_MASK, divisor << ISPTCTRL_CTRL_DIVA_SHIFT); dev_dbg(isp->dev, "isp_set_xclk(): cam_xclka set to %d Hz\n", currentxclk); break; case ISP_XCLK_B: isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL, ISPTCTRL_CTRL_DIVB_MASK, divisor << ISPTCTRL_CTRL_DIVB_SHIFT); dev_dbg(isp->dev, "isp_set_xclk(): cam_xclkb set to %d Hz\n", currentxclk); break; case ISP_XCLK_NONE: default: omap3isp_put(isp); dev_dbg(isp->dev, "ISP_ERR: isp_set_xclk(): Invalid requested " "xclk. Must be 0 (A) or 1 (B).\n"); return -EINVAL; } /* Do we go from stable whatever to clock? */ if (divisor >= 2 && isp->xclk_divisor[xclksel - 1] < 2) omap3isp_get(isp); /* Stopping the clock. */ else if (divisor < 2 && isp->xclk_divisor[xclksel - 1] >= 2) omap3isp_put(isp); isp->xclk_divisor[xclksel - 1] = divisor; omap3isp_put(isp); return currentxclk; }
/* * ispccp2_if_enable - Enable CCP2 interface. * @ccp2: pointer to ISP CCP2 device * @enable: enable/disable flag */ static void ispccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable) { struct isp_device *isp = to_isp_device(ccp2); struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity); int i; if (enable && ccp2->vdds_csib) regulator_enable(ccp2->vdds_csib); /* Enable/Disable all the LCx channels */ for (i = 0; i < CCP2_LCx_CHANS_NUM; i++) isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(i), ISPCCP2_LCx_CTRL_CHAN_EN, enable ? ISPCCP2_LCx_CTRL_CHAN_EN : 0); /* Enable/Disable ccp2 interface in ccp2 mode */ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL, ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN, enable ? (ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN) : 0); /* For frame count propagation */ if (pipe->do_propagation) { /* We may want the Frame Start IRQ from LC0 */ if (enable) isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LC01_IRQENABLE, ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ); else isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LC01_IRQENABLE, ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ); } if (!enable && ccp2->vdds_csib) regulator_disable(ccp2->vdds_csib); }
/* * ccp2_if_enable - Enable CCP2 interface. * @ccp2: pointer to ISP CCP2 device * @enable: enable/disable flag */ static int ccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable) { struct isp_device *isp = to_isp_device(ccp2); int ret; int i; if (enable && ccp2->vdds_csib) { ret = regulator_enable(ccp2->vdds_csib); if (ret < 0) return ret; } /* Enable/Disable all the LCx channels */ for (i = 0; i < CCP2_LCx_CHANS_NUM; i++) isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(i), ISPCCP2_LCx_CTRL_CHAN_EN, enable ? ISPCCP2_LCx_CTRL_CHAN_EN : 0); /* Enable/Disable ccp2 interface in ccp2 mode */ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL, ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN, enable ? (ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN) : 0); if (!enable && ccp2->vdds_csib) regulator_disable(ccp2->vdds_csib); return 0; }
/* * ispccp2_mem_enable - Enable CCP2 memory interface. * @ccp2: pointer to ISP CCP2 device * @enable: enable/disable flag */ static void ispccp2_mem_enable(struct isp_ccp2_device *ccp2, u8 enable) { struct isp_device *isp = to_isp_device(ccp2); if (enable) ispccp2_if_enable(ccp2, 0); /* Enable/Disable ccp2 interface in ccp2 mode */ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL, ISPCCP2_CTRL_MODE, enable ? ISPCCP2_CTRL_MODE : 0); isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_CTRL, ISPCCP2_LCM_CTRL_CHAN_EN, enable ? ISPCCP2_LCM_CTRL_CHAN_EN : 0); }
static void ccp2_mem_enable(struct isp_ccp2_device *ccp2, u8 enable) { struct isp_device *isp = to_isp_device(ccp2); if (enable) ccp2_if_enable(ccp2, 0); isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL, ISPCCP2_CTRL_MODE, enable ? ISPCCP2_CTRL_MODE : 0); isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_CTRL, ISPCCP2_LCM_CTRL_CHAN_EN, enable ? ISPCCP2_LCM_CTRL_CHAN_EN : 0); }
/* * csi2_if_enable - Enable CSI2 Receiver interface. * @enable: enable flag * */ static void csi2_if_enable(struct isp_device *isp, struct isp_csi2_device *csi2, u8 enable) { struct isp_csi2_ctrl_cfg *currctrl = &csi2->ctrl; isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_CTRL, ISPCSI2_CTRL_IF_EN, enable ? ISPCSI2_CTRL_IF_EN : 0); currctrl->if_enable = enable; }
static void ccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable) { struct isp_device *isp = to_isp_device(ccp2); struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity); int i; if (enable && ccp2->vdds_csib) regulator_enable(ccp2->vdds_csib); for (i = 0; i < CCP2_LCx_CHANS_NUM; i++) isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(i), ISPCCP2_LCx_CTRL_CHAN_EN, enable ? ISPCCP2_LCx_CTRL_CHAN_EN : 0); isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL, ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN, enable ? (ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN) : 0); if (pipe->do_propagation) { if (enable) isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LC01_IRQENABLE, ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ); else isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LC01_IRQENABLE, ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ); } if (!enable && ccp2->vdds_csib) regulator_disable(ccp2->vdds_csib); }
/* * omap3isp_csi2_reset - Resets the CSI2 module. * * Must be called with the phy lock held. * * Returns 0 if successful, or -EBUSY if power command didn't respond. */ int omap3isp_csi2_reset(struct isp_csi2_device *csi2) { struct isp_device *isp = csi2->isp; u8 soft_reset_retries = 0; u32 reg; int i; if (!csi2->available) return -ENODEV; if (csi2->phy->phy_in_use) return -EBUSY; isp_reg_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG, ISPCSI2_SYSCONFIG_SOFT_RESET); do { reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_SYSSTATUS) & ISPCSI2_SYSSTATUS_RESET_DONE; if (reg == ISPCSI2_SYSSTATUS_RESET_DONE) break; soft_reset_retries++; if (soft_reset_retries < 5) udelay(100); } while (soft_reset_retries < 5); if (soft_reset_retries == 5) { dev_err(isp->dev, "CSI2: Soft reset try count exceeded!\n"); return -EBUSY; } if (isp->revision == ISP_REVISION_15_0) isp_reg_set(isp, csi2->regs1, ISPCSI2_PHY_CFG, ISPCSI2_PHY_CFG_RESET_CTRL); i = 100; do { reg = isp_reg_readl(isp, csi2->phy->phy_regs, ISPCSIPHY_REG1) & ISPCSIPHY_REG1_RESET_DONE_CTRLCLK; if (reg == ISPCSIPHY_REG1_RESET_DONE_CTRLCLK) break; udelay(100); } while (--i > 0); if (i == 0) { dev_err(isp->dev, "CSI2: Reset for CSI2_96M_FCLK domain Failed!\n"); return -EBUSY; } if (isp->autoidle) isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG, ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK | ISPCSI2_SYSCONFIG_AUTO_IDLE, ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SMART | ((isp->revision == ISP_REVISION_15_0) ? ISPCSI2_SYSCONFIG_AUTO_IDLE : 0)); else isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG, ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK | ISPCSI2_SYSCONFIG_AUTO_IDLE, ISPCSI2_SYSCONFIG_MSTANDBY_MODE_NO); return 0; }