Skip to content

Commit c121ed0

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 d21a0db commit c121ed0

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
@@ -103,6 +103,12 @@ MODULE_PARM_DESC(fstrobe_delay, "Set fstrobe delay from end all lines starting t
103103
#define IMX477_DGTL_GAIN_DEFAULT 0x0100
104104
#define IMX477_DGTL_GAIN_STEP 1
105105

106+
#define IMX477_REG_IOP_SYSCK_DIV CCI_REG8(0x030b)
107+
#define IMX477_IOP_SYSCK_DIV 0x02
108+
#define IMX477_REG_IOP_PREDIV CCI_REG8(0x030d)
109+
#define IMX477_IOP_PREDIV 0x02
110+
#define IMX477_REG_IOP_MPY CCI_REG16(0x030e)
111+
106112
/* Test Pattern Control */
107113
#define IMX477_REG_TEST_PATTERN CCI_REG8(0x0600)
108114
#define IMX477_TEST_PATTERN_DISABLE 0
@@ -177,83 +183,6 @@ struct imx477_mode {
177183
struct imx477_reg_list reg_list;
178184
};
179185

180-
/* Link frequency setup */
181-
enum {
182-
IMX477_LINK_FREQ_450MHZ,
183-
IMX477_LINK_FREQ_453MHZ,
184-
IMX477_LINK_FREQ_456MHZ,
185-
IMX477_LINK_FREQ_459MHZ,
186-
IMX477_LINK_FREQ_462MHZ,
187-
IMX477_LINK_FREQ_498MHZ,
188-
};
189-
190-
static const s64 link_freqs[] = {
191-
[IMX477_LINK_FREQ_450MHZ] = 450000000,
192-
[IMX477_LINK_FREQ_453MHZ] = 453000000,
193-
[IMX477_LINK_FREQ_456MHZ] = 456000000,
194-
[IMX477_LINK_FREQ_459MHZ] = 459000000,
195-
[IMX477_LINK_FREQ_462MHZ] = 462000000,
196-
[IMX477_LINK_FREQ_498MHZ] = 498000000,
197-
};
198-
199-
/* 450MHz is the nominal "default" link frequency */
200-
static const struct cci_reg_sequence link_450Mhz_regs[] = {
201-
{CCI_REG8(0x030e), 0x00},
202-
{CCI_REG8(0x030f), 0x96},
203-
};
204-
205-
static const struct cci_reg_sequence link_453Mhz_regs[] = {
206-
{CCI_REG8(0x030e), 0x00},
207-
{CCI_REG8(0x030f), 0x97},
208-
};
209-
210-
static const struct cci_reg_sequence link_456Mhz_regs[] = {
211-
{CCI_REG8(0x030e), 0x00},
212-
{CCI_REG8(0x030f), 0x98},
213-
};
214-
215-
static const struct cci_reg_sequence link_459Mhz_regs[] = {
216-
{CCI_REG8(0x030e), 0x00},
217-
{CCI_REG8(0x030f), 0x99},
218-
};
219-
220-
static const struct cci_reg_sequence link_462Mhz_regs[] = {
221-
{CCI_REG8(0x030e), 0x00},
222-
{CCI_REG8(0x030f), 0x9a},
223-
};
224-
225-
static const struct cci_reg_sequence link_498Mhz_regs[] = {
226-
{CCI_REG8(0x030e), 0x00},
227-
{CCI_REG8(0x030f), 0xa6},
228-
};
229-
230-
static const struct imx477_reg_list link_freq_regs[] = {
231-
[IMX477_LINK_FREQ_450MHZ] = {
232-
.regs = link_450Mhz_regs,
233-
.num_of_regs = ARRAY_SIZE(link_450Mhz_regs)
234-
},
235-
[IMX477_LINK_FREQ_453MHZ] = {
236-
.regs = link_453Mhz_regs,
237-
.num_of_regs = ARRAY_SIZE(link_453Mhz_regs)
238-
},
239-
[IMX477_LINK_FREQ_456MHZ] = {
240-
.regs = link_456Mhz_regs,
241-
.num_of_regs = ARRAY_SIZE(link_456Mhz_regs)
242-
},
243-
[IMX477_LINK_FREQ_459MHZ] = {
244-
.regs = link_459Mhz_regs,
245-
.num_of_regs = ARRAY_SIZE(link_459Mhz_regs)
246-
},
247-
[IMX477_LINK_FREQ_462MHZ] = {
248-
.regs = link_462Mhz_regs,
249-
.num_of_regs = ARRAY_SIZE(link_462Mhz_regs)
250-
},
251-
[IMX477_LINK_FREQ_498MHZ] = {
252-
.regs = link_498Mhz_regs,
253-
.num_of_regs = ARRAY_SIZE(link_498Mhz_regs)
254-
},
255-
};
256-
257186
static const struct cci_reg_sequence mode_common_regs[] = {
258187
{CCI_REG8(0x0136), 0x18},
259188
{CCI_REG8(0x0137), 0x00},
@@ -581,8 +510,8 @@ static const struct cci_reg_sequence mode_common_regs[] = {
581510
{CCI_REG8(0x9e9f), 0x00},
582511
{CCI_REG8(0x0301), 0x05},
583512
{CCI_REG8(0x0303), 0x02},
584-
{CCI_REG8(0x030b), 0x02},
585-
{CCI_REG8(0x030d), 0x02},
513+
{IMX477_REG_IOP_SYSCK_DIV, IMX477_IOP_SYSCK_DIV},
514+
{IMX477_REG_IOP_PREDIV, IMX477_IOP_PREDIV},
586515
{CCI_REG8(0x0310), 0x01},
587516
{CCI_REG8(0x0820), 0x07},
588517
{CCI_REG8(0x0821), 0x08},
@@ -1125,7 +1054,8 @@ struct imx477 {
11251054
struct v4l2_ctrl *vblank;
11261055
struct v4l2_ctrl *hblank;
11271056

1128-
unsigned int link_freq_idx;
1057+
u64 link_freq_value;
1058+
u16 iop_pll_mpy;
11291059

11301060
/* Current mode */
11311061
const struct imx477_mode *mode;
@@ -1630,7 +1560,7 @@ static int imx477_get_selection(struct v4l2_subdev *sd,
16301560
static int imx477_start_streaming(struct imx477 *imx477)
16311561
{
16321562
struct i2c_client *client = v4l2_get_subdevdata(&imx477->sd);
1633-
const struct imx477_reg_list *reg_list, *freq_regs;
1563+
const struct imx477_reg_list *reg_list;
16341564
const struct imx477_reg_list *extra_regs;
16351565
unsigned int fst_width;
16361566
unsigned int fst_mult;
@@ -1644,10 +1574,9 @@ static int imx477_start_streaming(struct imx477 *imx477)
16441574
cci_multi_reg_write(imx477->regmap, extra_regs->regs,
16451575
extra_regs->num_of_regs, &ret);
16461576

1647-
/* Update the link frequency registers */
1648-
freq_regs = &link_freq_regs[imx477->link_freq_idx];
1649-
cci_multi_reg_write(imx477->regmap, freq_regs->regs,
1650-
freq_regs->num_of_regs, &ret);
1577+
/* Update the link frequency PLL multiplier register */
1578+
cci_write(imx477->regmap, IMX477_REG_IOP_MPY,
1579+
imx477->iop_pll_mpy, &ret);
16511580

16521581
if (ret) {
16531582
dev_err(&client->dev, "%s failed to set common settings\n",
@@ -1962,7 +1891,7 @@ static int imx477_init_controls(struct imx477 *imx477)
19621891
imx477->link_freq =
19631892
v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx477_ctrl_ops,
19641893
V4L2_CID_LINK_FREQ, 0, 0,
1965-
&link_freqs[imx477->link_freq_idx]);
1894+
&imx477->link_freq_value);
19661895
if (imx477->link_freq)
19671896
imx477->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
19681897

@@ -2061,6 +1990,25 @@ static void imx477_free_controls(struct imx477 *imx477)
20611990
mutex_destroy(&imx477->mutex);
20621991
}
20631992

1993+
static int imx477_check_link_freq(u64 link_frequency, u16 *mpy_out)
1994+
{
1995+
u64 mpy = link_frequency * 2 * IMX477_IOP_SYSCK_DIV * IMX477_IOP_PREDIV;
1996+
u64 tmp;
1997+
1998+
do_div(mpy, IMX477_XCLK_FREQ);
1999+
2000+
tmp = mpy * (IMX477_XCLK_FREQ / IMX477_IOP_PREDIV);
2001+
do_div(tmp, IMX477_IOP_SYSCK_DIV * 2);
2002+
2003+
if (tmp != link_frequency)
2004+
return -EINVAL;
2005+
2006+
if (mpy_out)
2007+
*mpy_out = mpy;
2008+
2009+
return 0;
2010+
}
2011+
20642012
static int imx477_check_hwcfg(struct device *dev, struct imx477 *imx477)
20652013
{
20662014
struct fwnode_handle *endpoint;
@@ -2093,16 +2041,16 @@ static int imx477_check_hwcfg(struct device *dev, struct imx477 *imx477)
20932041
goto error_out;
20942042
}
20952043

2096-
for (i = 0; i < ARRAY_SIZE(link_freqs); i++) {
2097-
if (link_freqs[i] == ep_cfg.link_frequencies[0]) {
2098-
imx477->link_freq_idx = i;
2044+
for (i = 0; i < ep_cfg.nr_of_link_frequencies; i++) {
2045+
if (!imx477_check_link_freq(ep_cfg.link_frequencies[i],
2046+
&imx477->iop_pll_mpy)) {
2047+
imx477->link_freq_value = ep_cfg.link_frequencies[i];
20992048
break;
21002049
}
21012050
}
21022051

2103-
if (i == ARRAY_SIZE(link_freqs)) {
2104-
dev_err(dev, "Link frequency not supported: %lld\n",
2105-
ep_cfg.link_frequencies[0]);
2052+
if (i == ep_cfg.nr_of_link_frequencies) {
2053+
dev_err(dev, "No supported link frequency configured\n");
21062054
ret = -EINVAL;
21072055
goto error_out;
21082056
}

0 commit comments

Comments
 (0)