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_SELECT (1 << 21)
53 #define MIPI_CAL_CONFIG_HSPDOS(x) (((x) & 0x1f) << 16)
54 #define MIPI_CAL_CONFIG_HSPUOS(x) (((x) & 0x1f) << 8)
55 #define MIPI_CAL_CONFIG_TERMOS(x) (((x) & 0x1f) << 0)
57 #define MIPI_CAL_BIAS_PAD_CFG0 0x16
58 #define MIPI_CAL_BIAS_PAD_PDVCLAMP (1 << 1)
59 #define MIPI_CAL_BIAS_PAD_E_VCLAMP_REF (1 << 0)
61 #define MIPI_CAL_BIAS_PAD_CFG1 0x17
63 #define MIPI_CAL_BIAS_PAD_CFG2 0x18
64 #define MIPI_CAL_BIAS_PAD_PDVREG (1 << 1)
66 static const struct module
{
69 { .reg
= MIPI_CAL_CONFIG_CSIA
},
70 { .reg
= MIPI_CAL_CONFIG_CSIB
},
71 { .reg
= MIPI_CAL_CONFIG_CSIC
},
72 { .reg
= MIPI_CAL_CONFIG_CSID
},
73 { .reg
= MIPI_CAL_CONFIG_CSIE
},
74 { .reg
= MIPI_CAL_CONFIG_DSIA
},
75 { .reg
= MIPI_CAL_CONFIG_DSIB
},
76 { .reg
= MIPI_CAL_CONFIG_DSIC
},
77 { .reg
= MIPI_CAL_CONFIG_DSID
},
86 struct tegra_mipi_device
{
87 struct platform_device
*pdev
;
88 struct tegra_mipi
*mipi
;
89 struct device
*device
;
93 static inline unsigned long tegra_mipi_readl(struct tegra_mipi
*mipi
,
96 return readl(mipi
->regs
+ (reg
<< 2));
99 static inline void tegra_mipi_writel(struct tegra_mipi
*mipi
,
100 unsigned long value
, unsigned long reg
)
102 writel(value
, mipi
->regs
+ (reg
<< 2));
105 struct tegra_mipi_device
*tegra_mipi_request(struct device
*device
)
107 struct device_node
*np
= device
->of_node
;
108 struct tegra_mipi_device
*dev
;
109 struct of_phandle_args args
;
112 err
= of_parse_phandle_with_args(np
, "nvidia,mipi-calibrate",
113 "#nvidia,mipi-calibrate-cells", 0,
118 dev
= kzalloc(sizeof(*dev
), GFP_KERNEL
);
120 of_node_put(args
.np
);
125 dev
->pdev
= of_find_device_by_node(args
.np
);
127 of_node_put(args
.np
);
132 of_node_put(args
.np
);
134 dev
->mipi
= platform_get_drvdata(dev
->pdev
);
140 dev
->pads
= args
.args
[0];
141 dev
->device
= device
;
146 platform_device_put(dev
->pdev
);
152 EXPORT_SYMBOL(tegra_mipi_request
);
154 void tegra_mipi_free(struct tegra_mipi_device
*device
)
156 platform_device_put(device
->pdev
);
159 EXPORT_SYMBOL(tegra_mipi_free
);
161 static int tegra_mipi_wait(struct tegra_mipi
*mipi
)
163 unsigned long timeout
= jiffies
+ msecs_to_jiffies(250);
166 while (time_before(jiffies
, timeout
)) {
167 value
= tegra_mipi_readl(mipi
, MIPI_CAL_STATUS
);
168 if ((value
& MIPI_CAL_STATUS_ACTIVE
) == 0 &&
169 (value
& MIPI_CAL_STATUS_DONE
) != 0)
172 usleep_range(10, 50);
178 int tegra_mipi_calibrate(struct tegra_mipi_device
*device
)
184 err
= clk_enable(device
->mipi
->clk
);
188 mutex_lock(&device
->mipi
->lock
);
190 value
= tegra_mipi_readl(device
->mipi
, MIPI_CAL_BIAS_PAD_CFG0
);
191 value
&= ~MIPI_CAL_BIAS_PAD_PDVCLAMP
;
192 value
|= MIPI_CAL_BIAS_PAD_E_VCLAMP_REF
;
193 tegra_mipi_writel(device
->mipi
, value
, MIPI_CAL_BIAS_PAD_CFG0
);
195 value
= tegra_mipi_readl(device
->mipi
, MIPI_CAL_BIAS_PAD_CFG2
);
196 value
&= ~MIPI_CAL_BIAS_PAD_PDVREG
;
197 tegra_mipi_writel(device
->mipi
, value
, MIPI_CAL_BIAS_PAD_CFG2
);
199 for (i
= 0; i
< ARRAY_SIZE(modules
); i
++) {
200 if (device
->pads
& BIT(i
))
201 value
= MIPI_CAL_CONFIG_SELECT
|
202 MIPI_CAL_CONFIG_HSPDOS(0) |
203 MIPI_CAL_CONFIG_HSPUOS(4) |
204 MIPI_CAL_CONFIG_TERMOS(5);
208 tegra_mipi_writel(device
->mipi
, value
, modules
[i
].reg
);
211 tegra_mipi_writel(device
->mipi
, MIPI_CAL_CTRL_START
, MIPI_CAL_CTRL
);
213 err
= tegra_mipi_wait(device
->mipi
);
215 mutex_unlock(&device
->mipi
->lock
);
216 clk_disable(device
->mipi
->clk
);
220 EXPORT_SYMBOL(tegra_mipi_calibrate
);
222 static int tegra_mipi_probe(struct platform_device
*pdev
)
224 struct tegra_mipi
*mipi
;
225 struct resource
*res
;
228 mipi
= devm_kzalloc(&pdev
->dev
, sizeof(*mipi
), GFP_KERNEL
);
232 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
233 mipi
->regs
= devm_ioremap_resource(&pdev
->dev
, res
);
234 if (IS_ERR(mipi
->regs
))
235 return PTR_ERR(mipi
->regs
);
237 mutex_init(&mipi
->lock
);
239 mipi
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
240 if (IS_ERR(mipi
->clk
)) {
241 dev_err(&pdev
->dev
, "failed to get clock\n");
242 return PTR_ERR(mipi
->clk
);
245 err
= clk_prepare(mipi
->clk
);
249 platform_set_drvdata(pdev
, mipi
);
254 static int tegra_mipi_remove(struct platform_device
*pdev
)
256 struct tegra_mipi
*mipi
= platform_get_drvdata(pdev
);
258 clk_unprepare(mipi
->clk
);
263 static struct of_device_id tegra_mipi_of_match
[] = {
264 { .compatible
= "nvidia,tegra114-mipi", },
268 struct platform_driver tegra_mipi_driver
= {
270 .name
= "tegra-mipi",
271 .of_match_table
= tegra_mipi_of_match
,
273 .probe
= tegra_mipi_probe
,
274 .remove
= tegra_mipi_remove
,