1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (c) 2011-2018 Magewell Electronics Co., Ltd. (Nanjing) 4 * Author: Yong Deng <yong.deng@magewell.com> 5 * Copyright 2021-2022 Bootlin 6 * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com> 7 */ 8 9 #include <linux/clk.h> 10 #include <linux/err.h> 11 #include <linux/interrupt.h> 12 #include <linux/module.h> 13 #include <linux/of.h> 14 #include <linux/of_device.h> 15 #include <linux/platform_device.h> 16 #include <linux/pm_runtime.h> 17 #include <linux/regmap.h> 18 #include <linux/reset.h> 19 #include <media/v4l2-device.h> 20 #include <media/v4l2-mc.h> 21 22 #include "sun6i_csi.h" 23 #include "sun6i_csi_bridge.h" 24 #include "sun6i_csi_capture.h" 25 #include "sun6i_csi_reg.h" 26 27 /* ISP */ 28 29 int sun6i_csi_isp_complete(struct sun6i_csi_device *csi_dev, 30 struct v4l2_device *v4l2_dev) 31 { 32 if (csi_dev->v4l2_dev && csi_dev->v4l2_dev != v4l2_dev) 33 return -EINVAL; 34 35 csi_dev->v4l2_dev = v4l2_dev; 36 csi_dev->media_dev = v4l2_dev->mdev; 37 38 return sun6i_csi_capture_setup(csi_dev); 39 } 40 41 static int sun6i_csi_isp_detect(struct sun6i_csi_device *csi_dev) 42 { 43 struct device *dev = csi_dev->dev; 44 struct fwnode_handle *handle; 45 46 /* 47 * ISP is not available if not connected via fwnode graph. 48 * This will also check that the remote parent node is available. 49 */ 50 handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 51 SUN6I_CSI_PORT_ISP, 0, 52 FWNODE_GRAPH_ENDPOINT_NEXT); 53 if (!handle) 54 return 0; 55 56 fwnode_handle_put(handle); 57 58 if (!IS_ENABLED(CONFIG_VIDEO_SUN6I_ISP)) { 59 dev_warn(dev, 60 "ISP link is detected but not enabled in kernel config!"); 61 return 0; 62 } 63 64 csi_dev->isp_available = true; 65 66 return 0; 67 } 68 69 /* Media */ 70 71 static const struct media_device_ops sun6i_csi_media_ops = { 72 .link_notify = v4l2_pipeline_link_notify, 73 }; 74 75 /* V4L2 */ 76 77 static int sun6i_csi_v4l2_setup(struct sun6i_csi_device *csi_dev) 78 { 79 struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; 80 struct media_device *media_dev = &v4l2->media_dev; 81 struct v4l2_device *v4l2_dev = &v4l2->v4l2_dev; 82 struct device *dev = csi_dev->dev; 83 int ret; 84 85 /* Media Device */ 86 87 strscpy(media_dev->model, SUN6I_CSI_DESCRIPTION, 88 sizeof(media_dev->model)); 89 media_dev->hw_revision = 0; 90 media_dev->ops = &sun6i_csi_media_ops; 91 media_dev->dev = dev; 92 93 media_device_init(media_dev); 94 95 ret = media_device_register(media_dev); 96 if (ret) { 97 dev_err(dev, "failed to register media device: %d\n", ret); 98 goto error_media; 99 } 100 101 /* V4L2 Device */ 102 103 v4l2_dev->mdev = media_dev; 104 105 ret = v4l2_device_register(dev, v4l2_dev); 106 if (ret) { 107 dev_err(dev, "failed to register v4l2 device: %d\n", ret); 108 goto error_media; 109 } 110 111 csi_dev->v4l2_dev = v4l2_dev; 112 csi_dev->media_dev = media_dev; 113 114 return 0; 115 116 error_media: 117 media_device_unregister(media_dev); 118 media_device_cleanup(media_dev); 119 120 return ret; 121 } 122 123 static void sun6i_csi_v4l2_cleanup(struct sun6i_csi_device *csi_dev) 124 { 125 struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; 126 127 media_device_unregister(&v4l2->media_dev); 128 v4l2_device_unregister(&v4l2->v4l2_dev); 129 media_device_cleanup(&v4l2->media_dev); 130 } 131 132 /* Platform */ 133 134 static irqreturn_t sun6i_csi_interrupt(int irq, void *private) 135 { 136 struct sun6i_csi_device *csi_dev = private; 137 bool capture_streaming = csi_dev->capture.state.streaming; 138 struct regmap *regmap = csi_dev->regmap; 139 u32 status = 0, enable = 0; 140 141 regmap_read(regmap, SUN6I_CSI_CH_INT_STA_REG, &status); 142 regmap_read(regmap, SUN6I_CSI_CH_INT_EN_REG, &enable); 143 144 if (!status) 145 return IRQ_NONE; 146 else if (!(status & enable) || !capture_streaming) 147 goto complete; 148 149 if ((status & SUN6I_CSI_CH_INT_STA_FIFO0_OF) || 150 (status & SUN6I_CSI_CH_INT_STA_FIFO1_OF) || 151 (status & SUN6I_CSI_CH_INT_STA_FIFO2_OF) || 152 (status & SUN6I_CSI_CH_INT_STA_HB_OF)) { 153 regmap_write(regmap, SUN6I_CSI_CH_INT_STA_REG, status); 154 155 regmap_update_bits(regmap, SUN6I_CSI_EN_REG, 156 SUN6I_CSI_EN_CSI_EN, 0); 157 regmap_update_bits(regmap, SUN6I_CSI_EN_REG, 158 SUN6I_CSI_EN_CSI_EN, SUN6I_CSI_EN_CSI_EN); 159 return IRQ_HANDLED; 160 } 161 162 if (status & SUN6I_CSI_CH_INT_STA_FD) 163 sun6i_csi_capture_frame_done(csi_dev); 164 165 if (status & SUN6I_CSI_CH_INT_STA_VS) 166 sun6i_csi_capture_sync(csi_dev); 167 168 complete: 169 regmap_write(regmap, SUN6I_CSI_CH_INT_STA_REG, status); 170 171 return IRQ_HANDLED; 172 } 173 174 static int sun6i_csi_suspend(struct device *dev) 175 { 176 struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev); 177 178 reset_control_assert(csi_dev->reset); 179 clk_disable_unprepare(csi_dev->clock_ram); 180 clk_disable_unprepare(csi_dev->clock_mod); 181 182 return 0; 183 } 184 185 static int sun6i_csi_resume(struct device *dev) 186 { 187 struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev); 188 int ret; 189 190 ret = reset_control_deassert(csi_dev->reset); 191 if (ret) { 192 dev_err(dev, "failed to deassert reset\n"); 193 return ret; 194 } 195 196 ret = clk_prepare_enable(csi_dev->clock_mod); 197 if (ret) { 198 dev_err(dev, "failed to enable module clock\n"); 199 goto error_reset; 200 } 201 202 ret = clk_prepare_enable(csi_dev->clock_ram); 203 if (ret) { 204 dev_err(dev, "failed to enable ram clock\n"); 205 goto error_clock_mod; 206 } 207 208 return 0; 209 210 error_clock_mod: 211 clk_disable_unprepare(csi_dev->clock_mod); 212 213 error_reset: 214 reset_control_assert(csi_dev->reset); 215 216 return ret; 217 } 218 219 static const struct dev_pm_ops sun6i_csi_pm_ops = { 220 .runtime_suspend = sun6i_csi_suspend, 221 .runtime_resume = sun6i_csi_resume, 222 }; 223 224 static const struct regmap_config sun6i_csi_regmap_config = { 225 .reg_bits = 32, 226 .reg_stride = 4, 227 .val_bits = 32, 228 .max_register = 0x9c, 229 }; 230 231 static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev, 232 struct platform_device *platform_dev) 233 { 234 struct device *dev = csi_dev->dev; 235 const struct sun6i_csi_variant *variant; 236 void __iomem *io_base; 237 int ret; 238 int irq; 239 240 variant = of_device_get_match_data(dev); 241 if (!variant) 242 return -EINVAL; 243 244 /* Registers */ 245 246 io_base = devm_platform_ioremap_resource(platform_dev, 0); 247 if (IS_ERR(io_base)) 248 return PTR_ERR(io_base); 249 250 csi_dev->regmap = devm_regmap_init_mmio_clk(dev, "bus", io_base, 251 &sun6i_csi_regmap_config); 252 if (IS_ERR(csi_dev->regmap)) { 253 dev_err(dev, "failed to init register map\n"); 254 return PTR_ERR(csi_dev->regmap); 255 } 256 257 /* Clocks */ 258 259 csi_dev->clock_mod = devm_clk_get(dev, "mod"); 260 if (IS_ERR(csi_dev->clock_mod)) { 261 dev_err(dev, "failed to acquire module clock\n"); 262 return PTR_ERR(csi_dev->clock_mod); 263 } 264 265 csi_dev->clock_ram = devm_clk_get(dev, "ram"); 266 if (IS_ERR(csi_dev->clock_ram)) { 267 dev_err(dev, "failed to acquire ram clock\n"); 268 return PTR_ERR(csi_dev->clock_ram); 269 } 270 271 ret = clk_set_rate_exclusive(csi_dev->clock_mod, 272 variant->clock_mod_rate); 273 if (ret) { 274 dev_err(dev, "failed to set mod clock rate\n"); 275 return ret; 276 } 277 278 /* Reset */ 279 280 csi_dev->reset = devm_reset_control_get_shared(dev, NULL); 281 if (IS_ERR(csi_dev->reset)) { 282 dev_err(dev, "failed to acquire reset\n"); 283 ret = PTR_ERR(csi_dev->reset); 284 goto error_clock_rate_exclusive; 285 } 286 287 /* Interrupt */ 288 289 irq = platform_get_irq(platform_dev, 0); 290 if (irq < 0) { 291 ret = -ENXIO; 292 goto error_clock_rate_exclusive; 293 } 294 295 ret = devm_request_irq(dev, irq, sun6i_csi_interrupt, IRQF_SHARED, 296 SUN6I_CSI_NAME, csi_dev); 297 if (ret) { 298 dev_err(dev, "failed to request interrupt\n"); 299 goto error_clock_rate_exclusive; 300 } 301 302 /* Runtime PM */ 303 304 pm_runtime_enable(dev); 305 306 return 0; 307 308 error_clock_rate_exclusive: 309 clk_rate_exclusive_put(csi_dev->clock_mod); 310 311 return ret; 312 } 313 314 static void sun6i_csi_resources_cleanup(struct sun6i_csi_device *csi_dev) 315 { 316 pm_runtime_disable(csi_dev->dev); 317 clk_rate_exclusive_put(csi_dev->clock_mod); 318 } 319 320 static int sun6i_csi_probe(struct platform_device *platform_dev) 321 { 322 struct sun6i_csi_device *csi_dev; 323 struct device *dev = &platform_dev->dev; 324 int ret; 325 326 csi_dev = devm_kzalloc(dev, sizeof(*csi_dev), GFP_KERNEL); 327 if (!csi_dev) 328 return -ENOMEM; 329 330 csi_dev->dev = &platform_dev->dev; 331 platform_set_drvdata(platform_dev, csi_dev); 332 333 ret = sun6i_csi_resources_setup(csi_dev, platform_dev); 334 if (ret) 335 return ret; 336 337 ret = sun6i_csi_isp_detect(csi_dev); 338 if (ret) 339 goto error_resources; 340 341 /* 342 * Register our own v4l2 and media devices when there is no ISP around. 343 * Otherwise the ISP will use async subdev registration with our bridge, 344 * which will provide v4l2 and media devices that are used to register 345 * the video interface. 346 */ 347 if (!csi_dev->isp_available) { 348 ret = sun6i_csi_v4l2_setup(csi_dev); 349 if (ret) 350 goto error_resources; 351 } 352 353 ret = sun6i_csi_bridge_setup(csi_dev); 354 if (ret) 355 goto error_v4l2; 356 357 if (!csi_dev->isp_available) { 358 ret = sun6i_csi_capture_setup(csi_dev); 359 if (ret) 360 goto error_bridge; 361 } 362 363 return 0; 364 365 error_bridge: 366 sun6i_csi_bridge_cleanup(csi_dev); 367 368 error_v4l2: 369 if (!csi_dev->isp_available) 370 sun6i_csi_v4l2_cleanup(csi_dev); 371 372 error_resources: 373 sun6i_csi_resources_cleanup(csi_dev); 374 375 return ret; 376 } 377 378 static int sun6i_csi_remove(struct platform_device *pdev) 379 { 380 struct sun6i_csi_device *csi_dev = platform_get_drvdata(pdev); 381 382 sun6i_csi_capture_cleanup(csi_dev); 383 sun6i_csi_bridge_cleanup(csi_dev); 384 385 if (!csi_dev->isp_available) 386 sun6i_csi_v4l2_cleanup(csi_dev); 387 388 sun6i_csi_resources_cleanup(csi_dev); 389 390 return 0; 391 } 392 393 static const struct sun6i_csi_variant sun6i_a31_csi_variant = { 394 .clock_mod_rate = 297000000, 395 }; 396 397 static const struct sun6i_csi_variant sun50i_a64_csi_variant = { 398 .clock_mod_rate = 300000000, 399 }; 400 401 static const struct of_device_id sun6i_csi_of_match[] = { 402 { 403 .compatible = "allwinner,sun6i-a31-csi", 404 .data = &sun6i_a31_csi_variant, 405 }, 406 { 407 .compatible = "allwinner,sun8i-a83t-csi", 408 .data = &sun6i_a31_csi_variant, 409 }, 410 { 411 .compatible = "allwinner,sun8i-h3-csi", 412 .data = &sun6i_a31_csi_variant, 413 }, 414 { 415 .compatible = "allwinner,sun8i-v3s-csi", 416 .data = &sun6i_a31_csi_variant, 417 }, 418 { 419 .compatible = "allwinner,sun50i-a64-csi", 420 .data = &sun50i_a64_csi_variant, 421 }, 422 {}, 423 }; 424 425 MODULE_DEVICE_TABLE(of, sun6i_csi_of_match); 426 427 static struct platform_driver sun6i_csi_platform_driver = { 428 .probe = sun6i_csi_probe, 429 .remove = sun6i_csi_remove, 430 .driver = { 431 .name = SUN6I_CSI_NAME, 432 .of_match_table = of_match_ptr(sun6i_csi_of_match), 433 .pm = &sun6i_csi_pm_ops, 434 }, 435 }; 436 437 module_platform_driver(sun6i_csi_platform_driver); 438 439 MODULE_DESCRIPTION("Allwinner A31 Camera Sensor Interface driver"); 440 MODULE_AUTHOR("Yong Deng <yong.deng@magewell.com>"); 441 MODULE_AUTHOR("Paul Kocialkowski <paul.kocialkowski@bootlin.com>"); 442 MODULE_LICENSE("GPL"); 443