Skip to content

Commit cb505be

Browse files
committed
media: imx477: Compute link frequency PLL settings
Rather than the hard coded PLL settings for fixed frequencies, compute the PLL settings based on device tree, validating that the specified rate can be achieved. Signed-off-by: Dave Stevenson <[email protected]>
1 parent 8a95009 commit cb505be

File tree

1 file changed

+40
-92
lines changed

1 file changed

+40
-92
lines changed

drivers/media/i2c/imx477.c

Lines changed: 40 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@ MODULE_PARM_DESC(trigger_mode, "Set vsync trigger mode: 1=source, 2=sink");
8787
#define IMX477_DGTL_GAIN_DEFAULT 0x0100
8888
#define IMX477_DGTL_GAIN_STEP 1
8989

90+
#define IMX477_REG_IOP_SYSCK_DIV CCI_REG8(0x030b)
91+
#define IMX477_IOP_SYSCK_DIV 0x02
92+
#define IMX477_REG_IOP_PREDIV CCI_REG8(0x030d)
93+
#define IMX477_IOP_PREDIV 0x02
94+
#define IMX477_REG_IOP_MPY CCI_REG16(0x030e)
95+
9096
/* Test Pattern Control */
9197
#define IMX477_REG_TEST_PATTERN CCI_REG8(0x0600)
9298
#define IMX477_TEST_PATTERN_DISABLE 0
@@ -161,83 +167,6 @@ struct imx477_mode {
161167
struct imx477_reg_list reg_list;
162168
};
163169

164-
/* Link frequency setup */
165-
enum {
166-
IMX477_LINK_FREQ_450MHZ,
167-
IMX477_LINK_FREQ_453MHZ,
168-
IMX477_LINK_FREQ_456MHZ,
169-
IMX477_LINK_FREQ_459MHZ,
170-
IMX477_LINK_FREQ_462MHZ,
171-
IMX477_LINK_FREQ_498MHZ,
172-
};
173-
174-
static const s64 link_freqs[] = {
175-
[IMX477_LINK_FREQ_450MHZ] = 450000000,
176-
[IMX477_LINK_FREQ_453MHZ] = 453000000,
177-
[IMX477_LINK_FREQ_456MHZ] = 456000000,
178-
[IMX477_LINK_FREQ_459MHZ] = 459000000,
179-
[IMX477_LINK_FREQ_462MHZ] = 462000000,
180-
[IMX477_LINK_FREQ_498MHZ] = 498000000,
181-
};
182-
183-
/* 450MHz is the nominal "default" link frequency */
184-
static const struct cci_reg_sequence link_450Mhz_regs[] = {
185-
{CCI_REG8(0x030e), 0x00},
186-
{CCI_REG8(0x030f), 0x96},
187-
};
188-
189-
static const struct cci_reg_sequence link_453Mhz_regs[] = {
190-
{CCI_REG8(0x030e), 0x00},
191-
{CCI_REG8(0x030f), 0x97},
192-
};
193-
194-
static const struct cci_reg_sequence link_456Mhz_regs[] = {
195-
{CCI_REG8(0x030e), 0x00},
196-
{CCI_REG8(0x030f), 0x98},
197-
};
198-
199-
static const struct cci_reg_sequence link_459Mhz_regs[] = {
200-
{CCI_REG8(0x030e), 0x00},
201-
{CCI_REG8(0x030f), 0x99},
202-
};
203-
204-
static const struct cci_reg_sequence link_462Mhz_regs[] = {
205-
{CCI_REG8(0x030e), 0x00},
206-
{CCI_REG8(0x030f), 0x9a},
207-
};
208-
209-
static const struct cci_reg_sequence link_498Mhz_regs[] = {
210-
{CCI_REG8(0x030e), 0x00},
211-
{CCI_REG8(0x030f), 0xa6},
212-
};
213-
214-
static const struct imx477_reg_list link_freq_regs[] = {
215-
[IMX477_LINK_FREQ_450MHZ] = {
216-
.regs = link_450Mhz_regs,
217-
.num_of_regs = ARRAY_SIZE(link_450Mhz_regs)
218-
},
219-
[IMX477_LINK_FREQ_453MHZ] = {
220-
.regs = link_453Mhz_regs,
221-
.num_of_regs = ARRAY_SIZE(link_453Mhz_regs)
222-
},
223-
[IMX477_LINK_FREQ_456MHZ] = {
224-
.regs = link_456Mhz_regs,
225-
.num_of_regs = ARRAY_SIZE(link_456Mhz_regs)
226-
},
227-
[IMX477_LINK_FREQ_459MHZ] = {
228-
.regs = link_459Mhz_regs,
229-
.num_of_regs = ARRAY_SIZE(link_459Mhz_regs)
230-
},
231-
[IMX477_LINK_FREQ_462MHZ] = {
232-
.regs = link_462Mhz_regs,
233-
.num_of_regs = ARRAY_SIZE(link_462Mhz_regs)
234-
},
235-
[IMX477_LINK_FREQ_498MHZ] = {
236-
.regs = link_498Mhz_regs,
237-
.num_of_regs = ARRAY_SIZE(link_498Mhz_regs)
238-
},
239-
};
240-
241170
static const struct cci_reg_sequence mode_common_regs[] = {
242171
{CCI_REG8(0x0136), 0x18},
243172
{CCI_REG8(0x0137), 0x00},
@@ -565,8 +494,8 @@ static const struct cci_reg_sequence mode_common_regs[] = {
565494
{CCI_REG8(0x9e9f), 0x00},
566495
{CCI_REG8(0x0301), 0x05},
567496
{CCI_REG8(0x0303), 0x02},
568-
{CCI_REG8(0x030b), 0x02},
569-
{CCI_REG8(0x030d), 0x02},
497+
{IMX477_REG_IOP_SYSCK_DIV, IMX477_IOP_SYSCK_DIV},
498+
{IMX477_REG_IOP_PREDIV, IMX477_IOP_PREDIV},
570499
{CCI_REG8(0x0310), 0x01},
571500
{CCI_REG8(0x0820), 0x07},
572501
{CCI_REG8(0x0821), 0x08},
@@ -1109,7 +1038,8 @@ struct imx477 {
11091038
struct v4l2_ctrl *vblank;
11101039
struct v4l2_ctrl *hblank;
11111040

1112-
unsigned int link_freq_idx;
1041+
u64 link_freq_value;
1042+
u16 iop_pll_mpy;
11131043

11141044
/* Current mode */
11151045
const struct imx477_mode *mode;
@@ -1614,7 +1544,7 @@ static int imx477_get_selection(struct v4l2_subdev *sd,
16141544
static int imx477_start_streaming(struct imx477 *imx477)
16151545
{
16161546
struct i2c_client *client = v4l2_get_subdevdata(&imx477->sd);
1617-
const struct imx477_reg_list *reg_list, *freq_regs;
1547+
const struct imx477_reg_list *reg_list;
16181548
const struct imx477_reg_list *extra_regs;
16191549
int ret, tm;
16201550

@@ -1626,10 +1556,9 @@ static int imx477_start_streaming(struct imx477 *imx477)
16261556
cci_multi_reg_write(imx477->regmap, extra_regs->regs,
16271557
extra_regs->num_of_regs, &ret);
16281558

1629-
/* Update the link frequency registers */
1630-
freq_regs = &link_freq_regs[imx477->link_freq_idx];
1631-
cci_multi_reg_write(imx477->regmap, freq_regs->regs,
1632-
freq_regs->num_of_regs, &ret);
1559+
/* Update the link frequency PLL multiplier register */
1560+
cci_write(imx477->regmap, IMX477_REG_IOP_MPY,
1561+
imx477->iop_pll_mpy, &ret);
16331562

16341563
if (ret) {
16351564
dev_err(&client->dev, "%s failed to set common settings\n",
@@ -1922,7 +1851,7 @@ static int imx477_init_controls(struct imx477 *imx477)
19221851
imx477->link_freq =
19231852
v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx477_ctrl_ops,
19241853
V4L2_CID_LINK_FREQ, 0, 0,
1925-
&link_freqs[imx477->link_freq_idx]);
1854+
&imx477->link_freq_value);
19261855
if (imx477->link_freq)
19271856
imx477->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
19281857

@@ -2021,6 +1950,25 @@ static void imx477_free_controls(struct imx477 *imx477)
20211950
mutex_destroy(&imx477->mutex);
20221951
}
20231952

1953+
static int imx477_check_link_freq(u64 link_frequency, u16 *mpy_out)
1954+
{
1955+
u64 mpy = link_frequency * 2 * IMX477_IOP_SYSCK_DIV * IMX477_IOP_PREDIV;
1956+
u64 tmp;
1957+
1958+
do_div(mpy, IMX477_XCLK_FREQ);
1959+
1960+
tmp = mpy * (IMX477_XCLK_FREQ / IMX477_IOP_PREDIV);
1961+
do_div(tmp, IMX477_IOP_SYSCK_DIV * 2);
1962+
1963+
if (tmp != link_frequency)
1964+
return -EINVAL;
1965+
1966+
if (mpy_out)
1967+
*mpy_out = mpy;
1968+
1969+
return 0;
1970+
}
1971+
20241972
static int imx477_check_hwcfg(struct device *dev, struct imx477 *imx477)
20251973
{
20261974
struct fwnode_handle *endpoint;
@@ -2053,16 +2001,16 @@ static int imx477_check_hwcfg(struct device *dev, struct imx477 *imx477)
20532001
goto error_out;
20542002
}
20552003

2056-
for (i = 0; i < ARRAY_SIZE(link_freqs); i++) {
2057-
if (link_freqs[i] == ep_cfg.link_frequencies[0]) {
2058-
imx477->link_freq_idx = i;
2004+
for (i = 0; i < ep_cfg.nr_of_link_frequencies; i++) {
2005+
if (!imx477_check_link_freq(ep_cfg.link_frequencies[i],
2006+
&imx477->iop_pll_mpy)) {
2007+
imx477->link_freq_value = ep_cfg.link_frequencies[i];
20592008
break;
20602009
}
20612010
}
20622011

2063-
if (i == ARRAY_SIZE(link_freqs)) {
2064-
dev_err(dev, "Link frequency not supported: %lld\n",
2065-
ep_cfg.link_frequencies[0]);
2012+
if (i == ep_cfg.nr_of_link_frequencies) {
2013+
dev_err(dev, "No supported link frequency configured\n");
20662014
ret = -EINVAL;
20672015
goto error_out;
20682016
}

0 commit comments

Comments
 (0)