1ceafdaacSMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0-only
2ceafdaacSMauro Carvalho Chehab /*
3ceafdaacSMauro Carvalho Chehab * ispcsiphy.c
4ceafdaacSMauro Carvalho Chehab *
5ceafdaacSMauro Carvalho Chehab * TI OMAP3 ISP - CSI PHY module
6ceafdaacSMauro Carvalho Chehab *
7ceafdaacSMauro Carvalho Chehab * Copyright (C) 2010 Nokia Corporation
8ceafdaacSMauro Carvalho Chehab * Copyright (C) 2009 Texas Instruments, Inc.
9ceafdaacSMauro Carvalho Chehab *
10ceafdaacSMauro Carvalho Chehab * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
11ceafdaacSMauro Carvalho Chehab * Sakari Ailus <sakari.ailus@iki.fi>
12ceafdaacSMauro Carvalho Chehab */
13ceafdaacSMauro Carvalho Chehab
14ceafdaacSMauro Carvalho Chehab #include <linux/delay.h>
15ceafdaacSMauro Carvalho Chehab #include <linux/device.h>
16ceafdaacSMauro Carvalho Chehab #include <linux/regmap.h>
17ceafdaacSMauro Carvalho Chehab #include <linux/regulator/consumer.h>
18ceafdaacSMauro Carvalho Chehab
19ceafdaacSMauro Carvalho Chehab #include "isp.h"
20ceafdaacSMauro Carvalho Chehab #include "ispreg.h"
21ceafdaacSMauro Carvalho Chehab #include "ispcsiphy.h"
22ceafdaacSMauro Carvalho Chehab
csiphy_routing_cfg_3630(struct isp_csiphy * phy,enum isp_interface_type iface,bool ccp2_strobe)23ceafdaacSMauro Carvalho Chehab static void csiphy_routing_cfg_3630(struct isp_csiphy *phy,
24ceafdaacSMauro Carvalho Chehab enum isp_interface_type iface,
25ceafdaacSMauro Carvalho Chehab bool ccp2_strobe)
26ceafdaacSMauro Carvalho Chehab {
27ceafdaacSMauro Carvalho Chehab u32 reg;
28ceafdaacSMauro Carvalho Chehab u32 shift, mode;
29ceafdaacSMauro Carvalho Chehab
30ceafdaacSMauro Carvalho Chehab regmap_read(phy->isp->syscon, phy->isp->syscon_offset, ®);
31ceafdaacSMauro Carvalho Chehab
32ceafdaacSMauro Carvalho Chehab switch (iface) {
33ceafdaacSMauro Carvalho Chehab default:
34ceafdaacSMauro Carvalho Chehab /* Should not happen in practice, but let's keep the compiler happy. */
356bf96911STom Rix return;
36ceafdaacSMauro Carvalho Chehab case ISP_INTERFACE_CCP2B_PHY1:
37ceafdaacSMauro Carvalho Chehab reg &= ~OMAP3630_CONTROL_CAMERA_PHY_CTRL_CSI1_RX_SEL_PHY2;
38ceafdaacSMauro Carvalho Chehab shift = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_PHY1_SHIFT;
39ceafdaacSMauro Carvalho Chehab break;
40ceafdaacSMauro Carvalho Chehab case ISP_INTERFACE_CSI2C_PHY1:
41ceafdaacSMauro Carvalho Chehab shift = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_PHY1_SHIFT;
42ceafdaacSMauro Carvalho Chehab mode = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_DPHY;
43ceafdaacSMauro Carvalho Chehab break;
44ceafdaacSMauro Carvalho Chehab case ISP_INTERFACE_CCP2B_PHY2:
45ceafdaacSMauro Carvalho Chehab reg |= OMAP3630_CONTROL_CAMERA_PHY_CTRL_CSI1_RX_SEL_PHY2;
46ceafdaacSMauro Carvalho Chehab shift = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_PHY2_SHIFT;
47ceafdaacSMauro Carvalho Chehab break;
48ceafdaacSMauro Carvalho Chehab case ISP_INTERFACE_CSI2A_PHY2:
49ceafdaacSMauro Carvalho Chehab shift = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_PHY2_SHIFT;
50ceafdaacSMauro Carvalho Chehab mode = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_DPHY;
51ceafdaacSMauro Carvalho Chehab break;
52ceafdaacSMauro Carvalho Chehab }
53ceafdaacSMauro Carvalho Chehab
54ceafdaacSMauro Carvalho Chehab /* Select data/clock or data/strobe mode for CCP2 */
55ceafdaacSMauro Carvalho Chehab if (iface == ISP_INTERFACE_CCP2B_PHY1 ||
56ceafdaacSMauro Carvalho Chehab iface == ISP_INTERFACE_CCP2B_PHY2) {
57ceafdaacSMauro Carvalho Chehab if (ccp2_strobe)
58ceafdaacSMauro Carvalho Chehab mode = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_CCP2_DATA_STROBE;
59ceafdaacSMauro Carvalho Chehab else
60ceafdaacSMauro Carvalho Chehab mode = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_CCP2_DATA_CLOCK;
61ceafdaacSMauro Carvalho Chehab }
62ceafdaacSMauro Carvalho Chehab
63ceafdaacSMauro Carvalho Chehab reg &= ~(OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_MASK << shift);
64ceafdaacSMauro Carvalho Chehab reg |= mode << shift;
65ceafdaacSMauro Carvalho Chehab
66ceafdaacSMauro Carvalho Chehab regmap_write(phy->isp->syscon, phy->isp->syscon_offset, reg);
67ceafdaacSMauro Carvalho Chehab }
68ceafdaacSMauro Carvalho Chehab
csiphy_routing_cfg_3430(struct isp_csiphy * phy,u32 iface,bool on,bool ccp2_strobe)69ceafdaacSMauro Carvalho Chehab static void csiphy_routing_cfg_3430(struct isp_csiphy *phy, u32 iface, bool on,
70ceafdaacSMauro Carvalho Chehab bool ccp2_strobe)
71ceafdaacSMauro Carvalho Chehab {
72ceafdaacSMauro Carvalho Chehab u32 csirxfe = OMAP343X_CONTROL_CSIRXFE_PWRDNZ
73ceafdaacSMauro Carvalho Chehab | OMAP343X_CONTROL_CSIRXFE_RESET;
74ceafdaacSMauro Carvalho Chehab
75ceafdaacSMauro Carvalho Chehab /* Only the CCP2B on PHY1 is configurable. */
76ceafdaacSMauro Carvalho Chehab if (iface != ISP_INTERFACE_CCP2B_PHY1)
77ceafdaacSMauro Carvalho Chehab return;
78ceafdaacSMauro Carvalho Chehab
79ceafdaacSMauro Carvalho Chehab if (!on) {
80ceafdaacSMauro Carvalho Chehab regmap_write(phy->isp->syscon, phy->isp->syscon_offset, 0);
81ceafdaacSMauro Carvalho Chehab return;
82ceafdaacSMauro Carvalho Chehab }
83ceafdaacSMauro Carvalho Chehab
84ceafdaacSMauro Carvalho Chehab if (ccp2_strobe)
85ceafdaacSMauro Carvalho Chehab csirxfe |= OMAP343X_CONTROL_CSIRXFE_SELFORM;
86ceafdaacSMauro Carvalho Chehab
87ceafdaacSMauro Carvalho Chehab regmap_write(phy->isp->syscon, phy->isp->syscon_offset, csirxfe);
88ceafdaacSMauro Carvalho Chehab }
89ceafdaacSMauro Carvalho Chehab
90ceafdaacSMauro Carvalho Chehab /*
91ceafdaacSMauro Carvalho Chehab * Configure OMAP 3 CSI PHY routing.
92ceafdaacSMauro Carvalho Chehab * @phy: relevant phy device
93ceafdaacSMauro Carvalho Chehab * @iface: ISP_INTERFACE_*
94ceafdaacSMauro Carvalho Chehab * @on: power on or off
95ceafdaacSMauro Carvalho Chehab * @ccp2_strobe: false: data/clock, true: data/strobe
96ceafdaacSMauro Carvalho Chehab *
97ceafdaacSMauro Carvalho Chehab * Note that the underlying routing configuration registers are part of the
98ceafdaacSMauro Carvalho Chehab * control (SCM) register space and part of the CORE power domain on both 3430
99ceafdaacSMauro Carvalho Chehab * and 3630, so they will not hold their contents in off-mode. This isn't an
100ceafdaacSMauro Carvalho Chehab * issue since the MPU power domain is forced on whilst the ISP is in use.
101ceafdaacSMauro Carvalho Chehab */
csiphy_routing_cfg(struct isp_csiphy * phy,enum isp_interface_type iface,bool on,bool ccp2_strobe)102ceafdaacSMauro Carvalho Chehab static void csiphy_routing_cfg(struct isp_csiphy *phy,
103ceafdaacSMauro Carvalho Chehab enum isp_interface_type iface, bool on,
104ceafdaacSMauro Carvalho Chehab bool ccp2_strobe)
105ceafdaacSMauro Carvalho Chehab {
106ceafdaacSMauro Carvalho Chehab if (phy->isp->phy_type == ISP_PHY_TYPE_3630 && on)
107ceafdaacSMauro Carvalho Chehab return csiphy_routing_cfg_3630(phy, iface, ccp2_strobe);
108ceafdaacSMauro Carvalho Chehab if (phy->isp->phy_type == ISP_PHY_TYPE_3430)
109ceafdaacSMauro Carvalho Chehab return csiphy_routing_cfg_3430(phy, iface, on, ccp2_strobe);
110ceafdaacSMauro Carvalho Chehab }
111ceafdaacSMauro Carvalho Chehab
112ceafdaacSMauro Carvalho Chehab /*
113ceafdaacSMauro Carvalho Chehab * csiphy_power_autoswitch_enable
114ceafdaacSMauro Carvalho Chehab * @enable: Sets or clears the autoswitch function enable flag.
115ceafdaacSMauro Carvalho Chehab */
csiphy_power_autoswitch_enable(struct isp_csiphy * phy,bool enable)116ceafdaacSMauro Carvalho Chehab static void csiphy_power_autoswitch_enable(struct isp_csiphy *phy, bool enable)
117ceafdaacSMauro Carvalho Chehab {
118ceafdaacSMauro Carvalho Chehab isp_reg_clr_set(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG,
119ceafdaacSMauro Carvalho Chehab ISPCSI2_PHY_CFG_PWR_AUTO,
120ceafdaacSMauro Carvalho Chehab enable ? ISPCSI2_PHY_CFG_PWR_AUTO : 0);
121ceafdaacSMauro Carvalho Chehab }
122ceafdaacSMauro Carvalho Chehab
123ceafdaacSMauro Carvalho Chehab /*
124ceafdaacSMauro Carvalho Chehab * csiphy_set_power
125ceafdaacSMauro Carvalho Chehab * @power: Power state to be set.
126ceafdaacSMauro Carvalho Chehab *
127ceafdaacSMauro Carvalho Chehab * Returns 0 if successful, or -EBUSY if the retry count is exceeded.
128ceafdaacSMauro Carvalho Chehab */
csiphy_set_power(struct isp_csiphy * phy,u32 power)129ceafdaacSMauro Carvalho Chehab static int csiphy_set_power(struct isp_csiphy *phy, u32 power)
130ceafdaacSMauro Carvalho Chehab {
131ceafdaacSMauro Carvalho Chehab u32 reg;
132ceafdaacSMauro Carvalho Chehab u8 retry_count;
133ceafdaacSMauro Carvalho Chehab
134ceafdaacSMauro Carvalho Chehab isp_reg_clr_set(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG,
135ceafdaacSMauro Carvalho Chehab ISPCSI2_PHY_CFG_PWR_CMD_MASK, power);
136ceafdaacSMauro Carvalho Chehab
137ceafdaacSMauro Carvalho Chehab retry_count = 0;
138ceafdaacSMauro Carvalho Chehab do {
139ceafdaacSMauro Carvalho Chehab udelay(50);
140ceafdaacSMauro Carvalho Chehab reg = isp_reg_readl(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG) &
141ceafdaacSMauro Carvalho Chehab ISPCSI2_PHY_CFG_PWR_STATUS_MASK;
142ceafdaacSMauro Carvalho Chehab
143ceafdaacSMauro Carvalho Chehab if (reg != power >> 2)
144ceafdaacSMauro Carvalho Chehab retry_count++;
145ceafdaacSMauro Carvalho Chehab
146ceafdaacSMauro Carvalho Chehab } while ((reg != power >> 2) && (retry_count < 100));
147ceafdaacSMauro Carvalho Chehab
148ceafdaacSMauro Carvalho Chehab if (retry_count == 100) {
149ceafdaacSMauro Carvalho Chehab dev_err(phy->isp->dev, "CSI2 CIO set power failed!\n");
150ceafdaacSMauro Carvalho Chehab return -EBUSY;
151ceafdaacSMauro Carvalho Chehab }
152ceafdaacSMauro Carvalho Chehab
153ceafdaacSMauro Carvalho Chehab return 0;
154ceafdaacSMauro Carvalho Chehab }
155ceafdaacSMauro Carvalho Chehab
156ceafdaacSMauro Carvalho Chehab /*
157ceafdaacSMauro Carvalho Chehab * TCLK values are OK at their reset values
158ceafdaacSMauro Carvalho Chehab */
159ceafdaacSMauro Carvalho Chehab #define TCLK_TERM 0
160ceafdaacSMauro Carvalho Chehab #define TCLK_MISS 1
161ceafdaacSMauro Carvalho Chehab #define TCLK_SETTLE 14
162ceafdaacSMauro Carvalho Chehab
omap3isp_csiphy_config(struct isp_csiphy * phy)163ceafdaacSMauro Carvalho Chehab static int omap3isp_csiphy_config(struct isp_csiphy *phy)
164ceafdaacSMauro Carvalho Chehab {
165ceafdaacSMauro Carvalho Chehab struct isp_pipeline *pipe = to_isp_pipeline(phy->entity);
166*c91fd7b7SSakari Ailus struct isp_bus_cfg *buscfg;
167ceafdaacSMauro Carvalho Chehab struct isp_csiphy_lanes_cfg *lanes;
168ceafdaacSMauro Carvalho Chehab int csi2_ddrclk_khz;
169ceafdaacSMauro Carvalho Chehab unsigned int num_data_lanes, used_lanes = 0;
170ceafdaacSMauro Carvalho Chehab unsigned int i;
171ceafdaacSMauro Carvalho Chehab u32 reg;
172ceafdaacSMauro Carvalho Chehab
173*c91fd7b7SSakari Ailus buscfg = v4l2_subdev_to_bus_cfg(pipe->external);
174*c91fd7b7SSakari Ailus if (WARN_ON(!buscfg))
175*c91fd7b7SSakari Ailus return -EPIPE;
176*c91fd7b7SSakari Ailus
177ceafdaacSMauro Carvalho Chehab if (buscfg->interface == ISP_INTERFACE_CCP2B_PHY1
178ceafdaacSMauro Carvalho Chehab || buscfg->interface == ISP_INTERFACE_CCP2B_PHY2) {
179ceafdaacSMauro Carvalho Chehab lanes = &buscfg->bus.ccp2.lanecfg;
180ceafdaacSMauro Carvalho Chehab num_data_lanes = 1;
181ceafdaacSMauro Carvalho Chehab } else {
182ceafdaacSMauro Carvalho Chehab lanes = &buscfg->bus.csi2.lanecfg;
183ceafdaacSMauro Carvalho Chehab num_data_lanes = buscfg->bus.csi2.num_data_lanes;
184ceafdaacSMauro Carvalho Chehab }
185ceafdaacSMauro Carvalho Chehab
186ceafdaacSMauro Carvalho Chehab if (num_data_lanes > phy->num_data_lanes)
187ceafdaacSMauro Carvalho Chehab return -EINVAL;
188ceafdaacSMauro Carvalho Chehab
189ceafdaacSMauro Carvalho Chehab /* Clock and data lanes verification */
190ceafdaacSMauro Carvalho Chehab for (i = 0; i < num_data_lanes; i++) {
191ceafdaacSMauro Carvalho Chehab if (lanes->data[i].pol > 1 || lanes->data[i].pos > 3)
192ceafdaacSMauro Carvalho Chehab return -EINVAL;
193ceafdaacSMauro Carvalho Chehab
194ceafdaacSMauro Carvalho Chehab if (used_lanes & (1 << lanes->data[i].pos))
195ceafdaacSMauro Carvalho Chehab return -EINVAL;
196ceafdaacSMauro Carvalho Chehab
197ceafdaacSMauro Carvalho Chehab used_lanes |= 1 << lanes->data[i].pos;
198ceafdaacSMauro Carvalho Chehab }
199ceafdaacSMauro Carvalho Chehab
200ceafdaacSMauro Carvalho Chehab if (lanes->clk.pol > 1 || lanes->clk.pos > 3)
201ceafdaacSMauro Carvalho Chehab return -EINVAL;
202ceafdaacSMauro Carvalho Chehab
203ceafdaacSMauro Carvalho Chehab if (lanes->clk.pos == 0 || used_lanes & (1 << lanes->clk.pos))
204ceafdaacSMauro Carvalho Chehab return -EINVAL;
205ceafdaacSMauro Carvalho Chehab
206ceafdaacSMauro Carvalho Chehab /*
207ceafdaacSMauro Carvalho Chehab * The PHY configuration is lost in off mode, that's not an
208ceafdaacSMauro Carvalho Chehab * issue since the MPU power domain is forced on whilst the
209ceafdaacSMauro Carvalho Chehab * ISP is in use.
210ceafdaacSMauro Carvalho Chehab */
211ceafdaacSMauro Carvalho Chehab csiphy_routing_cfg(phy, buscfg->interface, true,
212ceafdaacSMauro Carvalho Chehab buscfg->bus.ccp2.phy_layer);
213ceafdaacSMauro Carvalho Chehab
214ceafdaacSMauro Carvalho Chehab /* DPHY timing configuration */
215ceafdaacSMauro Carvalho Chehab /* CSI-2 is DDR and we only count used lanes. */
216ceafdaacSMauro Carvalho Chehab csi2_ddrclk_khz = pipe->external_rate / 1000
217ceafdaacSMauro Carvalho Chehab / (2 * hweight32(used_lanes)) * pipe->external_width;
218ceafdaacSMauro Carvalho Chehab
219ceafdaacSMauro Carvalho Chehab reg = isp_reg_readl(phy->isp, phy->phy_regs, ISPCSIPHY_REG0);
220ceafdaacSMauro Carvalho Chehab
221ceafdaacSMauro Carvalho Chehab reg &= ~(ISPCSIPHY_REG0_THS_TERM_MASK |
222ceafdaacSMauro Carvalho Chehab ISPCSIPHY_REG0_THS_SETTLE_MASK);
223ceafdaacSMauro Carvalho Chehab /* THS_TERM: Programmed value = ceil(12.5 ns/DDRClk period) - 1. */
224ceafdaacSMauro Carvalho Chehab reg |= (DIV_ROUND_UP(25 * csi2_ddrclk_khz, 2000000) - 1)
225ceafdaacSMauro Carvalho Chehab << ISPCSIPHY_REG0_THS_TERM_SHIFT;
226ceafdaacSMauro Carvalho Chehab /* THS_SETTLE: Programmed value = ceil(90 ns/DDRClk period) + 3. */
227ceafdaacSMauro Carvalho Chehab reg |= (DIV_ROUND_UP(90 * csi2_ddrclk_khz, 1000000) + 3)
228ceafdaacSMauro Carvalho Chehab << ISPCSIPHY_REG0_THS_SETTLE_SHIFT;
229ceafdaacSMauro Carvalho Chehab
230ceafdaacSMauro Carvalho Chehab isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG0);
231ceafdaacSMauro Carvalho Chehab
232ceafdaacSMauro Carvalho Chehab reg = isp_reg_readl(phy->isp, phy->phy_regs, ISPCSIPHY_REG1);
233ceafdaacSMauro Carvalho Chehab
234ceafdaacSMauro Carvalho Chehab reg &= ~(ISPCSIPHY_REG1_TCLK_TERM_MASK |
235ceafdaacSMauro Carvalho Chehab ISPCSIPHY_REG1_TCLK_MISS_MASK |
236ceafdaacSMauro Carvalho Chehab ISPCSIPHY_REG1_TCLK_SETTLE_MASK);
237ceafdaacSMauro Carvalho Chehab reg |= TCLK_TERM << ISPCSIPHY_REG1_TCLK_TERM_SHIFT;
238ceafdaacSMauro Carvalho Chehab reg |= TCLK_MISS << ISPCSIPHY_REG1_TCLK_MISS_SHIFT;
239ceafdaacSMauro Carvalho Chehab reg |= TCLK_SETTLE << ISPCSIPHY_REG1_TCLK_SETTLE_SHIFT;
240ceafdaacSMauro Carvalho Chehab
241ceafdaacSMauro Carvalho Chehab isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG1);
242ceafdaacSMauro Carvalho Chehab
243ceafdaacSMauro Carvalho Chehab /* DPHY lane configuration */
244ceafdaacSMauro Carvalho Chehab reg = isp_reg_readl(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG);
245ceafdaacSMauro Carvalho Chehab
246ceafdaacSMauro Carvalho Chehab for (i = 0; i < num_data_lanes; i++) {
247ceafdaacSMauro Carvalho Chehab reg &= ~(ISPCSI2_PHY_CFG_DATA_POL_MASK(i + 1) |
248ceafdaacSMauro Carvalho Chehab ISPCSI2_PHY_CFG_DATA_POSITION_MASK(i + 1));
249ceafdaacSMauro Carvalho Chehab reg |= (lanes->data[i].pol <<
250ceafdaacSMauro Carvalho Chehab ISPCSI2_PHY_CFG_DATA_POL_SHIFT(i + 1));
251ceafdaacSMauro Carvalho Chehab reg |= (lanes->data[i].pos <<
252ceafdaacSMauro Carvalho Chehab ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(i + 1));
253ceafdaacSMauro Carvalho Chehab }
254ceafdaacSMauro Carvalho Chehab
255ceafdaacSMauro Carvalho Chehab reg &= ~(ISPCSI2_PHY_CFG_CLOCK_POL_MASK |
256ceafdaacSMauro Carvalho Chehab ISPCSI2_PHY_CFG_CLOCK_POSITION_MASK);
257ceafdaacSMauro Carvalho Chehab reg |= lanes->clk.pol << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT;
258ceafdaacSMauro Carvalho Chehab reg |= lanes->clk.pos << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT;
259ceafdaacSMauro Carvalho Chehab
260ceafdaacSMauro Carvalho Chehab isp_reg_writel(phy->isp, reg, phy->cfg_regs, ISPCSI2_PHY_CFG);
261ceafdaacSMauro Carvalho Chehab
262ceafdaacSMauro Carvalho Chehab return 0;
263ceafdaacSMauro Carvalho Chehab }
264ceafdaacSMauro Carvalho Chehab
omap3isp_csiphy_acquire(struct isp_csiphy * phy,struct media_entity * entity)265ceafdaacSMauro Carvalho Chehab int omap3isp_csiphy_acquire(struct isp_csiphy *phy, struct media_entity *entity)
266ceafdaacSMauro Carvalho Chehab {
267ceafdaacSMauro Carvalho Chehab int rval;
268ceafdaacSMauro Carvalho Chehab
269ceafdaacSMauro Carvalho Chehab if (phy->vdd == NULL) {
270ceafdaacSMauro Carvalho Chehab dev_err(phy->isp->dev,
271ceafdaacSMauro Carvalho Chehab "Power regulator for CSI PHY not available\n");
272ceafdaacSMauro Carvalho Chehab return -ENODEV;
273ceafdaacSMauro Carvalho Chehab }
274ceafdaacSMauro Carvalho Chehab
275ceafdaacSMauro Carvalho Chehab mutex_lock(&phy->mutex);
276ceafdaacSMauro Carvalho Chehab
277ceafdaacSMauro Carvalho Chehab rval = regulator_enable(phy->vdd);
278ceafdaacSMauro Carvalho Chehab if (rval < 0)
279ceafdaacSMauro Carvalho Chehab goto done;
280ceafdaacSMauro Carvalho Chehab
281ceafdaacSMauro Carvalho Chehab rval = omap3isp_csi2_reset(phy->csi2);
282ceafdaacSMauro Carvalho Chehab if (rval < 0)
283ceafdaacSMauro Carvalho Chehab goto done;
284ceafdaacSMauro Carvalho Chehab
285ceafdaacSMauro Carvalho Chehab phy->entity = entity;
286ceafdaacSMauro Carvalho Chehab
287ceafdaacSMauro Carvalho Chehab rval = omap3isp_csiphy_config(phy);
288ceafdaacSMauro Carvalho Chehab if (rval < 0)
289ceafdaacSMauro Carvalho Chehab goto done;
290ceafdaacSMauro Carvalho Chehab
291ceafdaacSMauro Carvalho Chehab if (phy->isp->revision == ISP_REVISION_15_0) {
292ceafdaacSMauro Carvalho Chehab rval = csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_ON);
293ceafdaacSMauro Carvalho Chehab if (rval) {
294ceafdaacSMauro Carvalho Chehab regulator_disable(phy->vdd);
295ceafdaacSMauro Carvalho Chehab goto done;
296ceafdaacSMauro Carvalho Chehab }
297ceafdaacSMauro Carvalho Chehab
298ceafdaacSMauro Carvalho Chehab csiphy_power_autoswitch_enable(phy, true);
299ceafdaacSMauro Carvalho Chehab }
300ceafdaacSMauro Carvalho Chehab done:
301ceafdaacSMauro Carvalho Chehab if (rval < 0)
302ceafdaacSMauro Carvalho Chehab phy->entity = NULL;
303ceafdaacSMauro Carvalho Chehab
304ceafdaacSMauro Carvalho Chehab mutex_unlock(&phy->mutex);
305ceafdaacSMauro Carvalho Chehab return rval;
306ceafdaacSMauro Carvalho Chehab }
307ceafdaacSMauro Carvalho Chehab
omap3isp_csiphy_release(struct isp_csiphy * phy)308ceafdaacSMauro Carvalho Chehab void omap3isp_csiphy_release(struct isp_csiphy *phy)
309ceafdaacSMauro Carvalho Chehab {
310ceafdaacSMauro Carvalho Chehab mutex_lock(&phy->mutex);
311ceafdaacSMauro Carvalho Chehab if (phy->entity) {
312ceafdaacSMauro Carvalho Chehab struct isp_pipeline *pipe = to_isp_pipeline(phy->entity);
313*c91fd7b7SSakari Ailus struct isp_bus_cfg *buscfg;
314*c91fd7b7SSakari Ailus
315*c91fd7b7SSakari Ailus buscfg = v4l2_subdev_to_bus_cfg(pipe->external);
316*c91fd7b7SSakari Ailus if (WARN_ON(!buscfg)) {
317*c91fd7b7SSakari Ailus mutex_unlock(&phy->mutex);
318*c91fd7b7SSakari Ailus return;
319*c91fd7b7SSakari Ailus }
320ceafdaacSMauro Carvalho Chehab
321ceafdaacSMauro Carvalho Chehab csiphy_routing_cfg(phy, buscfg->interface, false,
322ceafdaacSMauro Carvalho Chehab buscfg->bus.ccp2.phy_layer);
323ceafdaacSMauro Carvalho Chehab if (phy->isp->revision == ISP_REVISION_15_0) {
324ceafdaacSMauro Carvalho Chehab csiphy_power_autoswitch_enable(phy, false);
325ceafdaacSMauro Carvalho Chehab csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_OFF);
326ceafdaacSMauro Carvalho Chehab }
327ceafdaacSMauro Carvalho Chehab regulator_disable(phy->vdd);
328ceafdaacSMauro Carvalho Chehab phy->entity = NULL;
329ceafdaacSMauro Carvalho Chehab }
330ceafdaacSMauro Carvalho Chehab mutex_unlock(&phy->mutex);
331ceafdaacSMauro Carvalho Chehab }
332ceafdaacSMauro Carvalho Chehab
333ceafdaacSMauro Carvalho Chehab /*
334ceafdaacSMauro Carvalho Chehab * omap3isp_csiphy_init - Initialize the CSI PHY frontends
335ceafdaacSMauro Carvalho Chehab */
omap3isp_csiphy_init(struct isp_device * isp)336ceafdaacSMauro Carvalho Chehab int omap3isp_csiphy_init(struct isp_device *isp)
337ceafdaacSMauro Carvalho Chehab {
338ceafdaacSMauro Carvalho Chehab struct isp_csiphy *phy1 = &isp->isp_csiphy1;
339ceafdaacSMauro Carvalho Chehab struct isp_csiphy *phy2 = &isp->isp_csiphy2;
340ceafdaacSMauro Carvalho Chehab
341ceafdaacSMauro Carvalho Chehab phy2->isp = isp;
342ceafdaacSMauro Carvalho Chehab phy2->csi2 = &isp->isp_csi2a;
343ceafdaacSMauro Carvalho Chehab phy2->num_data_lanes = ISP_CSIPHY2_NUM_DATA_LANES;
344ceafdaacSMauro Carvalho Chehab phy2->cfg_regs = OMAP3_ISP_IOMEM_CSI2A_REGS1;
345ceafdaacSMauro Carvalho Chehab phy2->phy_regs = OMAP3_ISP_IOMEM_CSIPHY2;
346ceafdaacSMauro Carvalho Chehab mutex_init(&phy2->mutex);
347ceafdaacSMauro Carvalho Chehab
348ceafdaacSMauro Carvalho Chehab phy1->isp = isp;
349ceafdaacSMauro Carvalho Chehab mutex_init(&phy1->mutex);
350ceafdaacSMauro Carvalho Chehab
351ceafdaacSMauro Carvalho Chehab if (isp->revision == ISP_REVISION_15_0) {
352ceafdaacSMauro Carvalho Chehab phy1->csi2 = &isp->isp_csi2c;
353ceafdaacSMauro Carvalho Chehab phy1->num_data_lanes = ISP_CSIPHY1_NUM_DATA_LANES;
354ceafdaacSMauro Carvalho Chehab phy1->cfg_regs = OMAP3_ISP_IOMEM_CSI2C_REGS1;
355ceafdaacSMauro Carvalho Chehab phy1->phy_regs = OMAP3_ISP_IOMEM_CSIPHY1;
356ceafdaacSMauro Carvalho Chehab }
357ceafdaacSMauro Carvalho Chehab
358ceafdaacSMauro Carvalho Chehab return 0;
359ceafdaacSMauro Carvalho Chehab }
360ceafdaacSMauro Carvalho Chehab
omap3isp_csiphy_cleanup(struct isp_device * isp)361ceafdaacSMauro Carvalho Chehab void omap3isp_csiphy_cleanup(struct isp_device *isp)
362ceafdaacSMauro Carvalho Chehab {
363ceafdaacSMauro Carvalho Chehab mutex_destroy(&isp->isp_csiphy1.mutex);
364ceafdaacSMauro Carvalho Chehab mutex_destroy(&isp->isp_csiphy2.mutex);
365ceafdaacSMauro Carvalho Chehab }
366