2 * Copyright (C) 2013 NVIDIA Corporation
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
23 #include <linux/clk.h>
24 #include <linux/delay.h>
25 #include <linux/host1x.h>
27 #include <linux/of_platform.h>
28 #include <linux/platform_device.h>
29 #include <linux/slab.h>
33 #define MIPI_CAL_CTRL 0x00
34 #define MIPI_CAL_CTRL_START (1 << 0)
36 #define MIPI_CAL_AUTOCAL_CTRL 0x01
38 #define MIPI_CAL_STATUS 0x02
39 #define MIPI_CAL_STATUS_DONE (1 << 16)
40 #define MIPI_CAL_STATUS_ACTIVE (1 << 0)
42 #define MIPI_CAL_CONFIG_CSIA 0x05
43 #define MIPI_CAL_CONFIG_CSIB 0x06
44 #define MIPI_CAL_CONFIG_CSIC 0x07
45 #define MIPI_CAL_CONFIG_CSID 0x08
46 #define MIPI_CAL_CONFIG_CSIE 0x09
47 #define MIPI_CAL_CONFIG_DSIA 0x0e
48 #define MIPI_CAL_CONFIG_DSIB 0x0f
49 #define MIPI_CAL_CONFIG_DSIC 0x10
50 #define MIPI_CAL_CONFIG_DSID 0x11
52 #define MIPI_CAL_CONFIG_DSIAB_CLK 0x19
53 #define MIPI_CAL_CONFIG_DSICD_CLK 0x1a
54 #define MIPI_CAL_CONFIG_CSIAB_CLK 0x1b
55 #define MIPI_CAL_CONFIG_CSICD_CLK 0x1c
56 #define MIPI_CAL_CONFIG_CSIE_CLK 0x1d
58 /* for data and clock lanes */
59 #define MIPI_CAL_CONFIG_SELECT (1 << 21)
62 #define MIPI_CAL_CONFIG_HSPDOS(x) (((x) & 0x1f) << 16)
63 #define MIPI_CAL_CONFIG_HSPUOS(x) (((x) & 0x1f) << 8)
64 #define MIPI_CAL_CONFIG_TERMOS(x) (((x) & 0x1f) << 0)
67 #define MIPI_CAL_CONFIG_HSCLKPDOSD(x) (((x) & 0x1f) << 8)
68 #define MIPI_CAL_CONFIG_HSCLKPUOSD(x) (((x) & 0x1f) << 0)
70 #define MIPI_CAL_BIAS_PAD_CFG0 0x16
71 #define MIPI_CAL_BIAS_PAD_PDVCLAMP (1 << 1)
72 #define MIPI_CAL_BIAS_PAD_E_VCLAMP_REF (1 << 0)
74 #define MIPI_CAL_BIAS_PAD_CFG1 0x17
75 #define MIPI_CAL_BIAS_PAD_DRV_DN_REF(x) (((x) & 0x7) << 16)
77 #define MIPI_CAL_BIAS_PAD_CFG2 0x18
78 #define MIPI_CAL_BIAS_PAD_PDVREG (1 << 1)
80 struct tegra_mipi_pad
{
85 struct tegra_mipi_soc
{
87 const struct tegra_mipi_pad
*pads
;
88 unsigned int num_pads
;
92 const struct tegra_mipi_soc
*soc
;
98 struct tegra_mipi_device
{
99 struct platform_device
*pdev
;
100 struct tegra_mipi
*mipi
;
101 struct device
*device
;
105 static inline u32
tegra_mipi_readl(struct tegra_mipi
*mipi
,
106 unsigned long offset
)
108 return readl(mipi
->regs
+ (offset
<< 2));
111 static inline void tegra_mipi_writel(struct tegra_mipi
*mipi
, u32 value
,
112 unsigned long offset
)
114 writel(value
, mipi
->regs
+ (offset
<< 2));
117 struct tegra_mipi_device
*tegra_mipi_request(struct device
*device
)
119 struct device_node
*np
= device
->of_node
;
120 struct tegra_mipi_device
*dev
;
121 struct of_phandle_args args
;
124 err
= of_parse_phandle_with_args(np
, "nvidia,mipi-calibrate",
125 "#nvidia,mipi-calibrate-cells", 0,
130 dev
= kzalloc(sizeof(*dev
), GFP_KERNEL
);
136 dev
->pdev
= of_find_device_by_node(args
.np
);
142 dev
->mipi
= platform_get_drvdata(dev
->pdev
);
148 of_node_put(args
.np
);
150 dev
->pads
= args
.args
[0];
151 dev
->device
= device
;
156 platform_device_put(dev
->pdev
);
160 of_node_put(args
.np
);
163 EXPORT_SYMBOL(tegra_mipi_request
);
165 void tegra_mipi_free(struct tegra_mipi_device
*device
)
167 platform_device_put(device
->pdev
);
170 EXPORT_SYMBOL(tegra_mipi_free
);
172 static int tegra_mipi_wait(struct tegra_mipi
*mipi
)
174 unsigned long timeout
= jiffies
+ msecs_to_jiffies(250);
177 while (time_before(jiffies
, timeout
)) {
178 value
= tegra_mipi_readl(mipi
, MIPI_CAL_STATUS
);
179 if ((value
& MIPI_CAL_STATUS_ACTIVE
) == 0 &&
180 (value
& MIPI_CAL_STATUS_DONE
) != 0)
183 usleep_range(10, 50);
189 int tegra_mipi_calibrate(struct tegra_mipi_device
*device
)
191 const struct tegra_mipi_soc
*soc
= device
->mipi
->soc
;
196 err
= clk_enable(device
->mipi
->clk
);
200 mutex_lock(&device
->mipi
->lock
);
202 value
= tegra_mipi_readl(device
->mipi
, MIPI_CAL_BIAS_PAD_CFG0
);
203 value
&= ~MIPI_CAL_BIAS_PAD_PDVCLAMP
;
204 value
|= MIPI_CAL_BIAS_PAD_E_VCLAMP_REF
;
205 tegra_mipi_writel(device
->mipi
, value
, MIPI_CAL_BIAS_PAD_CFG0
);
207 tegra_mipi_writel(device
->mipi
, MIPI_CAL_BIAS_PAD_DRV_DN_REF(2),
208 MIPI_CAL_BIAS_PAD_CFG1
);
210 value
= tegra_mipi_readl(device
->mipi
, MIPI_CAL_BIAS_PAD_CFG2
);
211 value
&= ~MIPI_CAL_BIAS_PAD_PDVREG
;
212 tegra_mipi_writel(device
->mipi
, value
, MIPI_CAL_BIAS_PAD_CFG2
);
214 for (i
= 0; i
< soc
->num_pads
; i
++) {
215 u32 clk
= 0, data
= 0;
217 if (device
->pads
& BIT(i
)) {
218 data
= MIPI_CAL_CONFIG_SELECT
|
219 MIPI_CAL_CONFIG_HSPDOS(0) |
220 MIPI_CAL_CONFIG_HSPUOS(4) |
221 MIPI_CAL_CONFIG_TERMOS(5);
222 clk
= MIPI_CAL_CONFIG_SELECT
|
223 MIPI_CAL_CONFIG_HSCLKPDOSD(0) |
224 MIPI_CAL_CONFIG_HSCLKPUOSD(4);
227 tegra_mipi_writel(device
->mipi
, data
, soc
->pads
[i
].data
);
229 if (soc
->has_clk_lane
)
230 tegra_mipi_writel(device
->mipi
, clk
, soc
->pads
[i
].clk
);
233 value
= tegra_mipi_readl(device
->mipi
, MIPI_CAL_CTRL
);
234 value
|= MIPI_CAL_CTRL_START
;
235 tegra_mipi_writel(device
->mipi
, value
, MIPI_CAL_CTRL
);
237 err
= tegra_mipi_wait(device
->mipi
);
239 mutex_unlock(&device
->mipi
->lock
);
240 clk_disable(device
->mipi
->clk
);
244 EXPORT_SYMBOL(tegra_mipi_calibrate
);
246 static const struct tegra_mipi_pad tegra114_mipi_pads
[] = {
247 { .data
= MIPI_CAL_CONFIG_CSIA
},
248 { .data
= MIPI_CAL_CONFIG_CSIB
},
249 { .data
= MIPI_CAL_CONFIG_CSIC
},
250 { .data
= MIPI_CAL_CONFIG_CSID
},
251 { .data
= MIPI_CAL_CONFIG_CSIE
},
252 { .data
= MIPI_CAL_CONFIG_DSIA
},
253 { .data
= MIPI_CAL_CONFIG_DSIB
},
254 { .data
= MIPI_CAL_CONFIG_DSIC
},
255 { .data
= MIPI_CAL_CONFIG_DSID
},
258 static const struct tegra_mipi_soc tegra114_mipi_soc
= {
259 .has_clk_lane
= false,
260 .pads
= tegra114_mipi_pads
,
261 .num_pads
= ARRAY_SIZE(tegra114_mipi_pads
),
264 static const struct tegra_mipi_pad tegra124_mipi_pads
[] = {
265 { .data
= MIPI_CAL_CONFIG_CSIA
, .clk
= MIPI_CAL_CONFIG_CSIAB_CLK
},
266 { .data
= MIPI_CAL_CONFIG_CSIB
, .clk
= MIPI_CAL_CONFIG_CSIAB_CLK
},
267 { .data
= MIPI_CAL_CONFIG_CSIC
, .clk
= MIPI_CAL_CONFIG_CSICD_CLK
},
268 { .data
= MIPI_CAL_CONFIG_CSID
, .clk
= MIPI_CAL_CONFIG_CSICD_CLK
},
269 { .data
= MIPI_CAL_CONFIG_CSIE
, .clk
= MIPI_CAL_CONFIG_CSIE_CLK
},
270 { .data
= MIPI_CAL_CONFIG_DSIA
, .clk
= MIPI_CAL_CONFIG_DSIAB_CLK
},
271 { .data
= MIPI_CAL_CONFIG_DSIB
, .clk
= MIPI_CAL_CONFIG_DSIAB_CLK
},
274 static const struct tegra_mipi_soc tegra124_mipi_soc
= {
275 .has_clk_lane
= true,
276 .pads
= tegra124_mipi_pads
,
277 .num_pads
= ARRAY_SIZE(tegra124_mipi_pads
),
280 static struct of_device_id tegra_mipi_of_match
[] = {
281 { .compatible
= "nvidia,tegra114-mipi", .data
= &tegra114_mipi_soc
},
282 { .compatible
= "nvidia,tegra124-mipi", .data
= &tegra124_mipi_soc
},
286 static int tegra_mipi_probe(struct platform_device
*pdev
)
288 const struct of_device_id
*match
;
289 struct tegra_mipi
*mipi
;
290 struct resource
*res
;
293 match
= of_match_node(tegra_mipi_of_match
, pdev
->dev
.of_node
);
297 mipi
= devm_kzalloc(&pdev
->dev
, sizeof(*mipi
), GFP_KERNEL
);
301 mipi
->soc
= match
->data
;
303 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
304 mipi
->regs
= devm_ioremap_resource(&pdev
->dev
, res
);
305 if (IS_ERR(mipi
->regs
))
306 return PTR_ERR(mipi
->regs
);
308 mutex_init(&mipi
->lock
);
310 mipi
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
311 if (IS_ERR(mipi
->clk
)) {
312 dev_err(&pdev
->dev
, "failed to get clock\n");
313 return PTR_ERR(mipi
->clk
);
316 err
= clk_prepare(mipi
->clk
);
320 platform_set_drvdata(pdev
, mipi
);
325 static int tegra_mipi_remove(struct platform_device
*pdev
)
327 struct tegra_mipi
*mipi
= platform_get_drvdata(pdev
);
329 clk_unprepare(mipi
->clk
);
334 struct platform_driver tegra_mipi_driver
= {
336 .name
= "tegra-mipi",
337 .of_match_table
= tegra_mipi_of_match
,
339 .probe
= tegra_mipi_probe
,
340 .remove
= tegra_mipi_remove
,