xref: /linux/drivers/gpu/host1x/mipi.c (revision d639d9fa162aadec1ae9980c4dcf6e50bd2f8290)
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 */
18 static 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  */
31 int 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 }
38 EXPORT_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  */
48 int 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 }
55 EXPORT_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  */
66 int 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 }
73 EXPORT_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  */
84 int 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 }
91 EXPORT_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  */
104 struct 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 		err = -ENODEV;
119 		goto out;
120 	}
121 
122 	mipidev = kzalloc_obj(*mipidev);
123 	if (!mipidev) {
124 		err = -ENOMEM;
125 		goto out;
126 	}
127 
128 	mipidev->pdev = of_find_device_by_node(args.np);
129 	if (!mipidev->pdev) {
130 		err = -ENODEV;
131 		goto free;
132 	}
133 
134 	of_node_put(args.np);
135 
136 	mipidev->ops = provider.ops;
137 	mipidev->pads = args.args[0];
138 
139 	return mipidev;
140 
141 free:
142 	kfree(mipidev);
143 out:
144 	of_node_put(args.np);
145 	return ERR_PTR(err);
146 }
147 EXPORT_SYMBOL(tegra_mipi_request);
148 
149 /**
150  * tegra_mipi_free - Free a Tegra MIPI calibration device.
151  * @mipidev: Handle to the Tegra MIPI calibration device.
152  *
153  * This function releases a reference to a Tegra MIPI calibration device
154  * previously requested by tegra_mipi_request().
155  */
156 void tegra_mipi_free(struct tegra_mipi_device *mipidev)
157 {
158 	platform_device_put(mipidev->pdev);
159 	kfree(mipidev);
160 }
161 EXPORT_SYMBOL(tegra_mipi_free);
162 
163 static void tegra_mipi_remove_provider(void *data)
164 {
165 	provider.np = NULL;
166 	provider.ops = NULL;
167 }
168 
169 /**
170  * devm_tegra_mipi_add_provider - Managed registration of a Tegra MIPI
171  *				  calibration function provider.
172  * @device: Handle to the device providing the MIPI calibration function.
173  * @np: Device node pointer of the device providing the MIPI calibration
174  *	function.
175  * @ops: Operations supported by the MIPI calibration device.
176  *
177  * This registers a device that provides MIPI calibration functions.
178  * For Tegra20 and Tegra30, this is the CSI block, while Tegra114 and
179  * newer SoC generations have a dedicated hardware block for these
180  * functions.
181  *
182  * Returns 0 on success or a negative error code on failure.
183  */
184 int devm_tegra_mipi_add_provider(struct device *device, struct device_node *np,
185 				 const struct tegra_mipi_ops *ops)
186 {
187 	if (provider.np)
188 		return -EBUSY;
189 
190 	provider.np = np;
191 	provider.ops = ops;
192 
193 	return devm_add_action_or_reset(device, tegra_mipi_remove_provider, NULL);
194 }
195 EXPORT_SYMBOL(devm_tegra_mipi_add_provider);
196