1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * stf_camss.c 4 * 5 * Starfive Camera Subsystem driver 6 * 7 * Copyright (C) 2021-2023 StarFive Technology Co., Ltd. 8 * 9 * Author: Jack Zhu <jack.zhu@starfivetech.com> 10 * Author: Changhuang Liang <changhuang.liang@starfivetech.com> 11 * 12 */ 13 #include <linux/module.h> 14 #include <linux/of.h> 15 #include <linux/of_graph.h> 16 #include <linux/platform_device.h> 17 #include <linux/pm_runtime.h> 18 #include <linux/videodev2.h> 19 #include <media/v4l2-fwnode.h> 20 #include <media/v4l2-mc.h> 21 22 #include "stf-camss.h" 23 24 static const char * const stfcamss_clocks[] = { 25 "wrapper_clk_c", 26 "ispcore_2x", 27 "isp_axi", 28 }; 29 30 static const char * const stfcamss_resets[] = { 31 "wrapper_p", 32 "wrapper_c", 33 "axiwr", 34 "isp_top_n", 35 "isp_top_axi", 36 }; 37 38 static const struct stf_isr_data stf_isrs[] = { 39 {"wr_irq", stf_wr_irq_handler}, 40 {"isp_irq", stf_isp_irq_handler}, 41 {"line_irq", stf_line_irq_handler}, 42 }; 43 44 static int stfcamss_get_mem_res(struct stfcamss *stfcamss) 45 { 46 struct platform_device *pdev = to_platform_device(stfcamss->dev); 47 48 stfcamss->syscon_base = 49 devm_platform_ioremap_resource_byname(pdev, "syscon"); 50 if (IS_ERR(stfcamss->syscon_base)) 51 return PTR_ERR(stfcamss->syscon_base); 52 53 stfcamss->isp_base = devm_platform_ioremap_resource_byname(pdev, "isp"); 54 if (IS_ERR(stfcamss->isp_base)) 55 return PTR_ERR(stfcamss->isp_base); 56 57 return 0; 58 } 59 60 /* 61 * stfcamss_of_parse_endpoint_node - Parse port endpoint node 62 * @dev: Device 63 * @node: Device node to be parsed 64 * @csd: Parsed data from port endpoint node 65 * 66 * Return 0 on success or a negative error code on failure 67 */ 68 static int stfcamss_of_parse_endpoint_node(struct stfcamss *stfcamss, 69 struct device_node *node, 70 struct stfcamss_async_subdev *csd) 71 { 72 struct v4l2_fwnode_endpoint vep = { { 0 } }; 73 int ret; 74 75 ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(node), &vep); 76 if (ret) { 77 dev_err(stfcamss->dev, "endpoint not defined at %pOF\n", node); 78 return ret; 79 } 80 81 csd->port = vep.base.port; 82 83 return 0; 84 } 85 86 /* 87 * stfcamss_of_parse_ports - Parse ports node 88 * @stfcamss: STFCAMSS device 89 * 90 * Return number of "port" nodes found in "ports" node 91 */ 92 static int stfcamss_of_parse_ports(struct stfcamss *stfcamss) 93 { 94 struct device_node *node = NULL; 95 int ret, num_subdevs = 0; 96 97 for_each_endpoint_of_node(stfcamss->dev->of_node, node) { 98 struct stfcamss_async_subdev *csd; 99 100 if (!of_device_is_available(node)) 101 continue; 102 103 csd = v4l2_async_nf_add_fwnode_remote(&stfcamss->notifier, 104 of_fwnode_handle(node), 105 struct stfcamss_async_subdev); 106 if (IS_ERR(csd)) { 107 ret = PTR_ERR(csd); 108 dev_err(stfcamss->dev, "failed to add async notifier\n"); 109 goto err_cleanup; 110 } 111 112 ret = stfcamss_of_parse_endpoint_node(stfcamss, node, csd); 113 if (ret) 114 goto err_cleanup; 115 116 num_subdevs++; 117 } 118 119 return num_subdevs; 120 121 err_cleanup: 122 of_node_put(node); 123 return ret; 124 } 125 126 static int stfcamss_register_devs(struct stfcamss *stfcamss) 127 { 128 struct stf_capture *cap_yuv = &stfcamss->captures[STF_CAPTURE_YUV]; 129 struct stf_isp_dev *isp_dev = &stfcamss->isp_dev; 130 int ret; 131 132 ret = stf_isp_register(isp_dev, &stfcamss->v4l2_dev); 133 if (ret < 0) { 134 dev_err(stfcamss->dev, 135 "failed to register stf isp%d entity: %d\n", 0, ret); 136 return ret; 137 } 138 139 ret = stf_capture_register(stfcamss, &stfcamss->v4l2_dev); 140 if (ret < 0) { 141 dev_err(stfcamss->dev, 142 "failed to register capture: %d\n", ret); 143 goto err_isp_unregister; 144 } 145 146 ret = media_create_pad_link(&isp_dev->subdev.entity, STF_ISP_PAD_SRC, 147 &cap_yuv->video.vdev.entity, 0, 0); 148 if (ret) 149 goto err_cap_unregister; 150 151 cap_yuv->video.source_subdev = &isp_dev->subdev; 152 153 return ret; 154 155 err_cap_unregister: 156 stf_capture_unregister(stfcamss); 157 err_isp_unregister: 158 stf_isp_unregister(&stfcamss->isp_dev); 159 160 return ret; 161 } 162 163 static void stfcamss_unregister_devs(struct stfcamss *stfcamss) 164 { 165 stf_isp_unregister(&stfcamss->isp_dev); 166 stf_capture_unregister(stfcamss); 167 } 168 169 static int stfcamss_subdev_notifier_bound(struct v4l2_async_notifier *async, 170 struct v4l2_subdev *subdev, 171 struct v4l2_async_connection *asc) 172 { 173 struct stfcamss *stfcamss = 174 container_of(async, struct stfcamss, notifier); 175 struct stfcamss_async_subdev *csd = 176 container_of(asc, struct stfcamss_async_subdev, asd); 177 enum stf_port_num port = csd->port; 178 struct stf_isp_dev *isp_dev = &stfcamss->isp_dev; 179 struct stf_capture *cap_raw = &stfcamss->captures[STF_CAPTURE_RAW]; 180 struct media_pad *pad; 181 int ret; 182 183 if (port == STF_PORT_CSI2RX) { 184 pad = &isp_dev->pads[STF_ISP_PAD_SINK]; 185 } else { 186 dev_err(stfcamss->dev, "not support port %d\n", port); 187 return -EPERM; 188 } 189 190 ret = v4l2_create_fwnode_links_to_pad(subdev, pad, 0); 191 if (ret) 192 return ret; 193 194 ret = media_create_pad_link(&subdev->entity, 1, 195 &cap_raw->video.vdev.entity, 0, 0); 196 if (ret) 197 return ret; 198 199 isp_dev->source_subdev = subdev; 200 cap_raw->video.source_subdev = subdev; 201 202 return 0; 203 } 204 205 static int stfcamss_subdev_notifier_complete(struct v4l2_async_notifier *ntf) 206 { 207 struct stfcamss *stfcamss = 208 container_of(ntf, struct stfcamss, notifier); 209 210 return v4l2_device_register_subdev_nodes(&stfcamss->v4l2_dev); 211 } 212 213 static const struct v4l2_async_notifier_operations 214 stfcamss_subdev_notifier_ops = { 215 .bound = stfcamss_subdev_notifier_bound, 216 .complete = stfcamss_subdev_notifier_complete, 217 }; 218 219 static void stfcamss_mc_init(struct platform_device *pdev, 220 struct stfcamss *stfcamss) 221 { 222 stfcamss->media_dev.dev = stfcamss->dev; 223 strscpy(stfcamss->media_dev.model, "Starfive Camera Subsystem", 224 sizeof(stfcamss->media_dev.model)); 225 media_device_init(&stfcamss->media_dev); 226 227 stfcamss->v4l2_dev.mdev = &stfcamss->media_dev; 228 } 229 230 /* 231 * stfcamss_probe - Probe STFCAMSS platform device 232 * @pdev: Pointer to STFCAMSS platform device 233 * 234 * Return 0 on success or a negative error code on failure 235 */ 236 static int stfcamss_probe(struct platform_device *pdev) 237 { 238 struct stfcamss *stfcamss; 239 struct device *dev = &pdev->dev; 240 int ret, num_subdevs; 241 unsigned int i; 242 243 stfcamss = devm_kzalloc(dev, sizeof(*stfcamss), GFP_KERNEL); 244 if (!stfcamss) 245 return -ENOMEM; 246 247 stfcamss->dev = dev; 248 249 for (i = 0; i < ARRAY_SIZE(stf_isrs); ++i) { 250 int irq; 251 252 irq = platform_get_irq(pdev, i); 253 if (irq < 0) 254 return irq; 255 256 ret = devm_request_irq(stfcamss->dev, irq, stf_isrs[i].isr, 0, 257 stf_isrs[i].name, stfcamss); 258 if (ret) { 259 dev_err(dev, "request irq failed: %d\n", ret); 260 return ret; 261 } 262 } 263 264 stfcamss->nclks = ARRAY_SIZE(stfcamss->sys_clk); 265 for (i = 0; i < stfcamss->nclks; ++i) 266 stfcamss->sys_clk[i].id = stfcamss_clocks[i]; 267 ret = devm_clk_bulk_get(dev, stfcamss->nclks, stfcamss->sys_clk); 268 if (ret) { 269 dev_err(dev, "Failed to get clk controls\n"); 270 return ret; 271 } 272 273 stfcamss->nrsts = ARRAY_SIZE(stfcamss->sys_rst); 274 for (i = 0; i < stfcamss->nrsts; ++i) 275 stfcamss->sys_rst[i].id = stfcamss_resets[i]; 276 ret = devm_reset_control_bulk_get_shared(dev, stfcamss->nrsts, 277 stfcamss->sys_rst); 278 if (ret) { 279 dev_err(dev, "Failed to get reset controls\n"); 280 return ret; 281 } 282 283 ret = stfcamss_get_mem_res(stfcamss); 284 if (ret) { 285 dev_err(dev, "Could not map registers\n"); 286 return ret; 287 } 288 289 platform_set_drvdata(pdev, stfcamss); 290 291 v4l2_async_nf_init(&stfcamss->notifier, &stfcamss->v4l2_dev); 292 293 num_subdevs = stfcamss_of_parse_ports(stfcamss); 294 if (num_subdevs < 0) { 295 ret = -ENODEV; 296 dev_err(dev, "Failed to get sub devices: %d\n", ret); 297 goto err_cleanup_notifier; 298 } 299 300 ret = stf_isp_init(stfcamss); 301 if (ret < 0) { 302 dev_err(dev, "Failed to init isp: %d\n", ret); 303 goto err_cleanup_notifier; 304 } 305 306 stfcamss_mc_init(pdev, stfcamss); 307 308 ret = v4l2_device_register(stfcamss->dev, &stfcamss->v4l2_dev); 309 if (ret < 0) { 310 dev_err(dev, "Failed to register V4L2 device: %d\n", ret); 311 goto err_cleanup_media_device; 312 } 313 314 ret = media_device_register(&stfcamss->media_dev); 315 if (ret) { 316 dev_err(dev, "Failed to register media device: %d\n", ret); 317 goto err_unregister_device; 318 } 319 320 ret = stfcamss_register_devs(stfcamss); 321 if (ret < 0) { 322 dev_err(dev, "Failed to register subdevice: %d\n", ret); 323 goto err_unregister_media_dev; 324 } 325 326 pm_runtime_enable(dev); 327 328 stfcamss->notifier.ops = &stfcamss_subdev_notifier_ops; 329 ret = v4l2_async_nf_register(&stfcamss->notifier); 330 if (ret) { 331 dev_err(dev, "Failed to register async subdev nodes: %d\n", 332 ret); 333 pm_runtime_disable(dev); 334 goto err_unregister_subdevs; 335 } 336 337 return 0; 338 339 err_unregister_subdevs: 340 stfcamss_unregister_devs(stfcamss); 341 err_unregister_media_dev: 342 media_device_unregister(&stfcamss->media_dev); 343 err_unregister_device: 344 v4l2_device_unregister(&stfcamss->v4l2_dev); 345 err_cleanup_media_device: 346 media_device_cleanup(&stfcamss->media_dev); 347 err_cleanup_notifier: 348 v4l2_async_nf_cleanup(&stfcamss->notifier); 349 return ret; 350 } 351 352 /* 353 * stfcamss_remove - Remove STFCAMSS platform device 354 * @pdev: Pointer to STFCAMSS platform device 355 * 356 * Always returns 0. 357 */ 358 static int stfcamss_remove(struct platform_device *pdev) 359 { 360 struct stfcamss *stfcamss = platform_get_drvdata(pdev); 361 362 stfcamss_unregister_devs(stfcamss); 363 v4l2_device_unregister(&stfcamss->v4l2_dev); 364 media_device_cleanup(&stfcamss->media_dev); 365 v4l2_async_nf_cleanup(&stfcamss->notifier); 366 pm_runtime_disable(&pdev->dev); 367 368 return 0; 369 } 370 371 static const struct of_device_id stfcamss_of_match[] = { 372 { .compatible = "starfive,jh7110-camss" }, 373 { /* sentinel */ }, 374 }; 375 376 MODULE_DEVICE_TABLE(of, stfcamss_of_match); 377 378 static int __maybe_unused stfcamss_runtime_suspend(struct device *dev) 379 { 380 struct stfcamss *stfcamss = dev_get_drvdata(dev); 381 int ret; 382 383 ret = reset_control_bulk_assert(stfcamss->nrsts, stfcamss->sys_rst); 384 if (ret) { 385 dev_err(dev, "reset assert failed\n"); 386 return ret; 387 } 388 389 clk_bulk_disable_unprepare(stfcamss->nclks, stfcamss->sys_clk); 390 391 return 0; 392 } 393 394 static int __maybe_unused stfcamss_runtime_resume(struct device *dev) 395 { 396 struct stfcamss *stfcamss = dev_get_drvdata(dev); 397 int ret; 398 399 ret = clk_bulk_prepare_enable(stfcamss->nclks, stfcamss->sys_clk); 400 if (ret) { 401 dev_err(dev, "clock prepare enable failed\n"); 402 return ret; 403 } 404 405 ret = reset_control_bulk_deassert(stfcamss->nrsts, stfcamss->sys_rst); 406 if (ret < 0) { 407 dev_err(dev, "cannot deassert resets\n"); 408 clk_bulk_disable_unprepare(stfcamss->nclks, stfcamss->sys_clk); 409 return ret; 410 } 411 412 return 0; 413 } 414 415 static const struct dev_pm_ops stfcamss_pm_ops = { 416 SET_RUNTIME_PM_OPS(stfcamss_runtime_suspend, 417 stfcamss_runtime_resume, 418 NULL) 419 }; 420 421 static struct platform_driver stfcamss_driver = { 422 .probe = stfcamss_probe, 423 .remove = stfcamss_remove, 424 .driver = { 425 .name = "starfive-camss", 426 .pm = &stfcamss_pm_ops, 427 .of_match_table = stfcamss_of_match, 428 }, 429 }; 430 431 module_platform_driver(stfcamss_driver); 432 433 MODULE_AUTHOR("Jack Zhu <jack.zhu@starfivetech.com>"); 434 MODULE_AUTHOR("Changhuang Liang <changhuang.liang@starfivetech.com>"); 435 MODULE_DESCRIPTION("StarFive Camera Subsystem driver"); 436 MODULE_LICENSE("GPL"); 437