Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2013 NVIDIA Corporation
4 * Copyright (C) 2025 Svyatoslav Ryhel <clamor95@gmail.com>
5 */
6
7#include <linux/clk.h>
8#include <linux/io.h>
9#include <linux/iopoll.h>
10#include <linux/module.h>
11#include <linux/of.h>
12#include <linux/of_platform.h>
13#include <linux/platform_device.h>
14#include <linux/slab.h>
15#include <linux/tegra-mipi-cal.h>
16
17/* only need to support one provider */
18static struct {
19 struct device_node *np;
20 const struct tegra_mipi_ops *ops;
21} provider;
22
23/**
24 * tegra_mipi_enable - Enable the Tegra MIPI calibration device.
25 * @device: Handle to the Tegra MIPI calibration device.
26 *
27 * This calls the enable sequence for the Tegra MIPI calibration device.
28 *
29 * Returns 0 on success or a negative error code on failure.
30 */
31int tegra_mipi_enable(struct tegra_mipi_device *device)
32{
33 if (device->ops->enable)
34 return device->ops->enable(device);
35
36 return 0;
37}
38EXPORT_SYMBOL(tegra_mipi_enable);
39
40/**
41 * tegra_mipi_disable - Disable the Tegra MIPI calibration device.
42 * @device: Handle to the Tegra MIPI calibration device.
43 *
44 * This calls the disable sequence for the Tegra MIPI calibration device.
45 *
46 * Returns 0 on success or a negative error code on failure.
47 */
48int tegra_mipi_disable(struct tegra_mipi_device *device)
49{
50 if (device->ops->disable)
51 return device->ops->disable(device);
52
53 return 0;
54}
55EXPORT_SYMBOL(tegra_mipi_disable);
56
57/**
58 * tegra_mipi_start_calibration - Start the Tegra MIPI calibration sequence.
59 * @device: Handle to the Tegra MIPI calibration device.
60 *
61 * This initiates the calibration of CSI/DSI interfaces via the Tegra MIPI
62 * calibration device.
63 *
64 * Returns 0 on success or a negative error code on failure.
65 */
66int tegra_mipi_start_calibration(struct tegra_mipi_device *device)
67{
68 if (device->ops->start_calibration)
69 return device->ops->start_calibration(device);
70
71 return 0;
72}
73EXPORT_SYMBOL(tegra_mipi_start_calibration);
74
75/**
76 * tegra_mipi_finish_calibration - Finish the Tegra MIPI calibration sequence.
77 * @device: Handle to the Tegra MIPI calibration device.
78 *
79 * This completes the calibration of CSI/DSI interfaces via the Tegra MIPI
80 * calibration device.
81 *
82 * Returns 0 on success or a negative error code on failure.
83 */
84int tegra_mipi_finish_calibration(struct tegra_mipi_device *device)
85{
86 if (device->ops->finish_calibration)
87 return device->ops->finish_calibration(device);
88
89 return 0;
90}
91EXPORT_SYMBOL(tegra_mipi_finish_calibration);
92
93/**
94 * tegra_mipi_request - Request a Tegra MIPI calibration device.
95 * @device: Handle of the device requesting the MIPI calibration function.
96 * @np: Device node pointer of the device requesting the MIPI calibration
97 * function.
98 *
99 * This function requests a reference to a Tegra MIPI calibration device.
100 *
101 * Returns a pointer to the Tegra MIPI calibration device on success,
102 * or an ERR_PTR-encoded error code on failure.
103 */
104struct tegra_mipi_device *tegra_mipi_request(struct device *device,
105 struct device_node *np)
106{
107 struct tegra_mipi_device *mipidev;
108 struct of_phandle_args args;
109 int err;
110
111 err = of_parse_phandle_with_args(np, "nvidia,mipi-calibrate",
112 "#nvidia,mipi-calibrate-cells", 0,
113 &args);
114 if (err < 0)
115 return ERR_PTR(err);
116
117 if (provider.np != args.np)
118 return ERR_PTR(-ENODEV);
119
120 mipidev = kzalloc_obj(*mipidev);
121 if (!mipidev) {
122 err = -ENOMEM;
123 goto out;
124 }
125
126 mipidev->pdev = of_find_device_by_node(args.np);
127 if (!mipidev->pdev) {
128 err = -ENODEV;
129 goto free;
130 }
131
132 of_node_put(args.np);
133
134 mipidev->ops = provider.ops;
135 mipidev->pads = args.args[0];
136
137 return mipidev;
138
139free:
140 kfree(mipidev);
141out:
142 of_node_put(args.np);
143 return ERR_PTR(err);
144}
145EXPORT_SYMBOL(tegra_mipi_request);
146
147/**
148 * tegra_mipi_free - Free a Tegra MIPI calibration device.
149 * @mipidev: Handle to the Tegra MIPI calibration device.
150 *
151 * This function releases a reference to a Tegra MIPI calibration device
152 * previously requested by tegra_mipi_request().
153 */
154void tegra_mipi_free(struct tegra_mipi_device *mipidev)
155{
156 platform_device_put(mipidev->pdev);
157 kfree(mipidev);
158}
159EXPORT_SYMBOL(tegra_mipi_free);
160
161static void tegra_mipi_remove_provider(void *data)
162{
163 provider.np = NULL;
164 provider.ops = NULL;
165}
166
167/**
168 * devm_tegra_mipi_add_provider - Managed registration of a Tegra MIPI
169 * calibration function provider.
170 * @device: Handle to the device providing the MIPI calibration function.
171 * @np: Device node pointer of the device providing the MIPI calibration
172 * function.
173 * @ops: Operations supported by the MIPI calibration device.
174 *
175 * This registers a device that provides MIPI calibration functions.
176 * For Tegra20 and Tegra30, this is the CSI block, while Tegra114 and
177 * newer SoC generations have a dedicated hardware block for these
178 * functions.
179 *
180 * Returns 0 on success or a negative error code on failure.
181 */
182int devm_tegra_mipi_add_provider(struct device *device, struct device_node *np,
183 const struct tegra_mipi_ops *ops)
184{
185 if (provider.np)
186 return -EBUSY;
187
188 provider.np = np;
189 provider.ops = ops;
190
191 return devm_add_action_or_reset(device, tegra_mipi_remove_provider, NULL);
192}
193EXPORT_SYMBOL(devm_tegra_mipi_add_provider);