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 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 139 free: 140 kfree(mipidev); 141 out: 142 of_node_put(args.np); 143 return ERR_PTR(err); 144 } 145 EXPORT_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 */ 154 void tegra_mipi_free(struct tegra_mipi_device *mipidev) 155 { 156 platform_device_put(mipidev->pdev); 157 kfree(mipidev); 158 } 159 EXPORT_SYMBOL(tegra_mipi_free); 160 161 static 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 */ 182 int 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 } 193 EXPORT_SYMBOL(devm_tegra_mipi_add_provider); 194