Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
drivers
media
i2c
aptina-pll.c
Go to the documentation of this file.
1
/*
2
* Aptina Sensor PLL Configuration
3
*
4
* Copyright (C) 2012 Laurent Pinchart <
[email protected]
>
5
*
6
* This program is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU General Public License
8
* version 2 as published by the Free Software Foundation.
9
*
10
* This program is distributed in the hope that it will be useful, but
11
* WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* General Public License for more details.
14
*
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18
* 02110-1301 USA
19
*/
20
21
#include <linux/device.h>
22
#include <
linux/gcd.h
>
23
#include <linux/kernel.h>
24
#include <
linux/lcm.h
>
25
#include <linux/module.h>
26
27
#include "
aptina-pll.h
"
28
29
int
aptina_pll_calculate
(
struct
device
*
dev
,
30
const
struct
aptina_pll_limits
*limits,
31
struct
aptina_pll
*
pll
)
32
{
33
unsigned
int
mf_min;
34
unsigned
int
mf_max;
35
unsigned
int
p1_min;
36
unsigned
int
p1_max;
37
unsigned
int
p1
;
38
unsigned
int
div
;
39
40
dev_dbg
(dev,
"PLL: ext clock %u pix clock %u\n"
,
41
pll->
ext_clock
, pll->
pix_clock
);
42
43
if
(pll->
ext_clock
< limits->
ext_clock_min
||
44
pll->
ext_clock
> limits->
ext_clock_max
) {
45
dev_err
(dev,
"pll: invalid external clock frequency.\n"
);
46
return
-
EINVAL
;
47
}
48
49
if
(pll->
pix_clock
== 0 || pll->
pix_clock
> limits->
pix_clock_max
) {
50
dev_err
(dev,
"pll: invalid pixel clock frequency.\n"
);
51
return
-
EINVAL
;
52
}
53
54
/* Compute the multiplier M and combined N*P1 divisor. */
55
div =
gcd
(pll->
pix_clock
, pll->
ext_clock
);
56
pll->
m
= pll->
pix_clock
/
div
;
57
div = pll->
ext_clock
/
div
;
58
59
/* We now have the smallest M and N*P1 values that will result in the
60
* desired pixel clock frequency, but they might be out of the valid
61
* range. Compute the factor by which we should multiply them given the
62
* following constraints:
63
*
64
* - minimum/maximum multiplier
65
* - minimum/maximum multiplier output clock frequency assuming the
66
* minimum/maximum N value
67
* - minimum/maximum combined N*P1 divisor
68
*/
69
mf_min =
DIV_ROUND_UP
(limits->
m_min
, pll->
m
);
70
mf_min =
max
(mf_min, limits->
out_clock_min
/
71
(pll->
ext_clock
/ limits->
n_min
* pll->
m
));
72
mf_min =
max
(mf_min, limits->
n_min
* limits->
p1_min
/ div);
73
mf_max = limits->
m_max
/ pll->
m
;
74
mf_max =
min
(mf_max, limits->
out_clock_max
/
75
(pll->
ext_clock
/ limits->
n_max
* pll->
m
));
76
mf_max =
min
(mf_max,
DIV_ROUND_UP
(limits->
n_max
* limits->
p1_max
, div));
77
78
dev_dbg
(dev,
"pll: mf min %u max %u\n"
, mf_min, mf_max);
79
if
(mf_min > mf_max) {
80
dev_err
(dev,
"pll: no valid combined N*P1 divisor.\n"
);
81
return
-
EINVAL
;
82
}
83
84
/*
85
* We're looking for the highest acceptable P1 value for which a
86
* multiplier factor MF exists that fulfills the following conditions:
87
*
88
* 1. p1 is in the [p1_min, p1_max] range given by the limits and is
89
* even
90
* 2. mf is in the [mf_min, mf_max] range computed above
91
* 3. div * mf is a multiple of p1, in order to compute
92
* n = div * mf / p1
93
* m = pll->m * mf
94
* 4. the internal clock frequency, given by ext_clock / n, is in the
95
* [int_clock_min, int_clock_max] range given by the limits
96
* 5. the output clock frequency, given by ext_clock / n * m, is in the
97
* [out_clock_min, out_clock_max] range given by the limits
98
*
99
* The first naive approach is to iterate over all p1 values acceptable
100
* according to (1) and all mf values acceptable according to (2), and
101
* stop at the first combination that fulfills (3), (4) and (5). This
102
* has a O(n^2) complexity.
103
*
104
* Instead of iterating over all mf values in the [mf_min, mf_max] range
105
* we can compute the mf increment between two acceptable values
106
* according to (3) with
107
*
108
* mf_inc = p1 / gcd(div, p1) (6)
109
*
110
* and round the minimum up to the nearest multiple of mf_inc. This will
111
* restrict the number of mf values to be checked.
112
*
113
* Furthermore, conditions (4) and (5) only restrict the range of
114
* acceptable p1 and mf values by modifying the minimum and maximum
115
* limits. (5) can be expressed as
116
*
117
* ext_clock / (div * mf / p1) * m * mf >= out_clock_min
118
* ext_clock / (div * mf / p1) * m * mf <= out_clock_max
119
*
120
* or
121
*
122
* p1 >= out_clock_min * div / (ext_clock * m) (7)
123
* p1 <= out_clock_max * div / (ext_clock * m)
124
*
125
* Similarly, (4) can be expressed as
126
*
127
* mf >= ext_clock * p1 / (int_clock_max * div) (8)
128
* mf <= ext_clock * p1 / (int_clock_min * div)
129
*
130
* We can thus iterate over the restricted p1 range defined by the
131
* combination of (1) and (7), and then compute the restricted mf range
132
* defined by the combination of (2), (6) and (8). If the resulting mf
133
* range is not empty, any value in the mf range is acceptable. We thus
134
* select the mf lwoer bound and the corresponding p1 value.
135
*/
136
if
(limits->
p1_min
== 0) {
137
dev_err
(dev,
"pll: P1 minimum value must be >0.\n"
);
138
return
-
EINVAL
;
139
}
140
141
p1_min =
max
(limits->
p1_min
,
DIV_ROUND_UP
(limits->
out_clock_min
* div,
142
pll->
ext_clock
* pll->
m
));
143
p1_max =
min
(limits->
p1_max
, limits->
out_clock_max
* div /
144
(pll->
ext_clock
* pll->
m
));
145
146
for
(p1 = p1_max & ~1; p1 >= p1_min; p1 -= 2) {
147
unsigned
int
mf_inc = p1 /
gcd
(div, p1);
148
unsigned
int
mf_high;
149
unsigned
int
mf_low;
150
151
mf_low =
roundup
(
max
(mf_min,
DIV_ROUND_UP
(pll->
ext_clock
* p1,
152
limits->
int_clock_max
* div)), mf_inc);
153
mf_high =
min
(mf_max, pll->
ext_clock
* p1 /
154
(limits->
int_clock_min
* div));
155
156
if
(mf_low > mf_high)
157
continue
;
158
159
pll->
n
= div * mf_low /
p1
;
160
pll->
m
*= mf_low;
161
pll->
p1
=
p1
;
162
dev_dbg
(dev,
"PLL: N %u M %u P1 %u\n"
, pll->
n
, pll->
m
, pll->
p1
);
163
return
0;
164
}
165
166
dev_err
(dev,
"pll: no valid N and P1 divisors found.\n"
);
167
return
-
EINVAL
;
168
}
169
EXPORT_SYMBOL_GPL
(
aptina_pll_calculate
);
170
171
MODULE_DESCRIPTION
(
"Aptina PLL Helpers"
);
172
MODULE_AUTHOR
(
"Laurent Pinchart <
[email protected]
>"
);
173
MODULE_LICENSE
(
"GPL v2"
);
Generated on Thu Jan 10 2013 13:46:25 for Linux Kernel by
1.8.2