1e6938cc1SHelen Koike // SPDX-License-Identifier: (GPL-2.0+ OR MIT) 2e6938cc1SHelen Koike /* 3e6938cc1SHelen Koike * Rockchip ISP1 Driver - Base driver 4e6938cc1SHelen Koike * 5e6938cc1SHelen Koike * Copyright (C) 2019 Collabora, Ltd. 6e6938cc1SHelen Koike * 7e6938cc1SHelen Koike * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd. 8e6938cc1SHelen Koike * Copyright (C) 2017 Rockchip Electronics Co., Ltd. 9e6938cc1SHelen Koike */ 10e6938cc1SHelen Koike 11e6938cc1SHelen Koike #include <linux/clk.h> 12e6938cc1SHelen Koike #include <linux/interrupt.h> 13e6938cc1SHelen Koike #include <linux/module.h> 14e6938cc1SHelen Koike #include <linux/of.h> 15e6938cc1SHelen Koike #include <linux/of_graph.h> 16e6938cc1SHelen Koike #include <linux/of_platform.h> 17e6938cc1SHelen Koike #include <linux/pinctrl/consumer.h> 18e6938cc1SHelen Koike #include <linux/phy/phy.h> 19e6938cc1SHelen Koike #include <linux/phy/phy-mipi-dphy.h> 20e6938cc1SHelen Koike #include <media/v4l2-fwnode.h> 21e6938cc1SHelen Koike 22e6938cc1SHelen Koike #include "rkisp1-common.h" 23e6938cc1SHelen Koike 24e6938cc1SHelen Koike /* 25e6938cc1SHelen Koike * ISP Details 26e6938cc1SHelen Koike * ----------- 27e6938cc1SHelen Koike * 28e6938cc1SHelen Koike * ISP Comprises with: 29e6938cc1SHelen Koike * MIPI serial camera interface 30e6938cc1SHelen Koike * Image Signal Processing 31e6938cc1SHelen Koike * Many Image Enhancement Blocks 32e6938cc1SHelen Koike * Crop 33e6938cc1SHelen Koike * Resizer 34e6938cc1SHelen Koike * RBG display ready image 35e6938cc1SHelen Koike * Image Rotation 36e6938cc1SHelen Koike * 37e6938cc1SHelen Koike * ISP Block Diagram 38e6938cc1SHelen Koike * ----------------- 39e6938cc1SHelen Koike * rkisp1-resizer.c rkisp1-capture.c 40e6938cc1SHelen Koike * |====================| |=======================| 41e6938cc1SHelen Koike * rkisp1-isp.c Main Picture Path 42e6938cc1SHelen Koike * |==========================| |===============================================| 43e6938cc1SHelen Koike * +-----------+ +--+--+--+--+ +--------+ +--------+ +-----------+ 44e6938cc1SHelen Koike * | | | | | | | | | | | | | 45e6938cc1SHelen Koike * +--------+ |\ | | | | | | | -->| Crop |->| RSZ |------------->| | 46e6938cc1SHelen Koike * | MIPI |--->| \ | | | | | | | | | | | | | | 47e6938cc1SHelen Koike * +--------+ | | | | |IE|IE|IE|IE| | +--------+ +--------+ | Memory | 48e6938cc1SHelen Koike * |MUX|--->| ISP |->|0 |1 |2 |3 |---+ | Interface | 49e6938cc1SHelen Koike * +--------+ | | | | | | | | | | +--------+ +--------+ +--------+ | | 50e6938cc1SHelen Koike * |Parallel|--->| / | | | | | | | | | | | | | | | | 51e6938cc1SHelen Koike * +--------+ |/ | | | | | | | -->| Crop |->| RSZ |->| RGB |->| | 52e6938cc1SHelen Koike * | | | | | | | | | | | | Rotate | | | 53e6938cc1SHelen Koike * +-----------+ +--+--+--+--+ +--------+ +--------+ +--------+ +-----------+ 54e6938cc1SHelen Koike * ^ 55e6938cc1SHelen Koike * +--------+ | |===============================================| 56e6938cc1SHelen Koike * | DMA |------------------------------------+ Self Picture Path 57e6938cc1SHelen Koike * +--------+ 58e6938cc1SHelen Koike * 59e6938cc1SHelen Koike * rkisp1-stats.c rkisp1-params.c 60e6938cc1SHelen Koike * |===============| |===============| 61e6938cc1SHelen Koike * +---------------+ +---------------+ 62e6938cc1SHelen Koike * | | | | 63e6938cc1SHelen Koike * | ISP | | ISP | 64e6938cc1SHelen Koike * | | | | 65e6938cc1SHelen Koike * +---------------+ +---------------+ 66e6938cc1SHelen Koike * 67e6938cc1SHelen Koike * 68e6938cc1SHelen Koike * Media Topology 69e6938cc1SHelen Koike * -------------- 70e6938cc1SHelen Koike * +----------+ +----------+ 71e6938cc1SHelen Koike * | Sensor 2 | | Sensor X | 72e6938cc1SHelen Koike * ------------ ... ------------ 73e6938cc1SHelen Koike * | 0 | | 0 | 74e6938cc1SHelen Koike * +----------+ +----------+ +-----------+ 75e6938cc1SHelen Koike * \ | | params | 76e6938cc1SHelen Koike * \ | | (output) | 77e6938cc1SHelen Koike * +----------+ \ | +-----------+ 78e6938cc1SHelen Koike * | Sensor 1 | v v | 79e6938cc1SHelen Koike * ------------ +------+------+ | 80e6938cc1SHelen Koike * | 0 |----->| 0 | 1 |<---------+ 81e6938cc1SHelen Koike * +----------+ |------+------| 82e6938cc1SHelen Koike * | ISP | 83e6938cc1SHelen Koike * |------+------| 84e6938cc1SHelen Koike * +-------------| 2 | 3 |----------+ 85e6938cc1SHelen Koike * | +------+------+ | 86e6938cc1SHelen Koike * | | | 87e6938cc1SHelen Koike * v v v 88e6938cc1SHelen Koike * +- ---------+ +-----------+ +-----------+ 89e6938cc1SHelen Koike * | 0 | | 0 | | stats | 90e6938cc1SHelen Koike * ------------- ------------- | (capture) | 91e6938cc1SHelen Koike * | Resizer | | Resizer | +-----------+ 92e6938cc1SHelen Koike * ------------| ------------| 93e6938cc1SHelen Koike * | 1 | | 1 | 94e6938cc1SHelen Koike * +-----------+ +-----------+ 95e6938cc1SHelen Koike * | | 96e6938cc1SHelen Koike * v v 97e6938cc1SHelen Koike * +-----------+ +-----------+ 98e6938cc1SHelen Koike * | selfpath | | mainpath | 99e6938cc1SHelen Koike * | (capture) | | (capture) | 100e6938cc1SHelen Koike * +-----------+ +-----------+ 101e6938cc1SHelen Koike */ 102e6938cc1SHelen Koike 10308818e6aSHeiko Stuebner struct rkisp1_isr_data { 10408818e6aSHeiko Stuebner const char *name; 10508818e6aSHeiko Stuebner irqreturn_t (*isr)(int irq, void *ctx); 10608818e6aSHeiko Stuebner }; 10708818e6aSHeiko Stuebner 108e6938cc1SHelen Koike struct rkisp1_match_data { 109e6938cc1SHelen Koike const char * const *clks; 11008818e6aSHeiko Stuebner unsigned int clk_size; 11108818e6aSHeiko Stuebner const struct rkisp1_isr_data *isrs; 11208818e6aSHeiko Stuebner unsigned int isr_size; 113fc672d80SHeiko Stuebner enum rkisp1_cif_isp_version isp_ver; 114e6938cc1SHelen Koike }; 115e6938cc1SHelen Koike 116e6938cc1SHelen Koike /* ---------------------------------------------------------------------------- 117e6938cc1SHelen Koike * Sensor DT bindings 118e6938cc1SHelen Koike */ 119e6938cc1SHelen Koike 120e6938cc1SHelen Koike static int rkisp1_create_links(struct rkisp1_device *rkisp1) 121e6938cc1SHelen Koike { 122e6938cc1SHelen Koike struct media_entity *source, *sink; 123e6938cc1SHelen Koike unsigned int flags, source_pad; 124e6938cc1SHelen Koike struct v4l2_subdev *sd; 125e6938cc1SHelen Koike unsigned int i; 126e6938cc1SHelen Koike int ret; 127e6938cc1SHelen Koike 128e6938cc1SHelen Koike /* sensor links */ 129e6938cc1SHelen Koike flags = MEDIA_LNK_FL_ENABLED; 130e6938cc1SHelen Koike list_for_each_entry(sd, &rkisp1->v4l2_dev.subdevs, list) { 131e6938cc1SHelen Koike if (sd == &rkisp1->isp.sd || 132e6938cc1SHelen Koike sd == &rkisp1->resizer_devs[RKISP1_MAINPATH].sd || 133e6938cc1SHelen Koike sd == &rkisp1->resizer_devs[RKISP1_SELFPATH].sd) 134e6938cc1SHelen Koike continue; 135e6938cc1SHelen Koike 136e6938cc1SHelen Koike ret = media_entity_get_fwnode_pad(&sd->entity, sd->fwnode, 137e6938cc1SHelen Koike MEDIA_PAD_FL_SOURCE); 138e6938cc1SHelen Koike if (ret < 0) { 139e6938cc1SHelen Koike dev_err(rkisp1->dev, "failed to find src pad for %s\n", 140e6938cc1SHelen Koike sd->name); 141e6938cc1SHelen Koike return ret; 142e6938cc1SHelen Koike } 143e6938cc1SHelen Koike source_pad = ret; 144e6938cc1SHelen Koike 145e6938cc1SHelen Koike ret = media_create_pad_link(&sd->entity, source_pad, 146e6938cc1SHelen Koike &rkisp1->isp.sd.entity, 147e6938cc1SHelen Koike RKISP1_ISP_PAD_SINK_VIDEO, 148e6938cc1SHelen Koike flags); 149e6938cc1SHelen Koike if (ret) 150e6938cc1SHelen Koike return ret; 151e6938cc1SHelen Koike 152e6938cc1SHelen Koike flags = 0; 153e6938cc1SHelen Koike } 154e6938cc1SHelen Koike 155e6938cc1SHelen Koike flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE; 156e6938cc1SHelen Koike 157e6938cc1SHelen Koike /* create ISP->RSZ->CAP links */ 158e6938cc1SHelen Koike for (i = 0; i < 2; i++) { 159e6938cc1SHelen Koike source = &rkisp1->isp.sd.entity; 160e6938cc1SHelen Koike sink = &rkisp1->resizer_devs[i].sd.entity; 161e6938cc1SHelen Koike ret = media_create_pad_link(source, RKISP1_ISP_PAD_SOURCE_VIDEO, 162e6938cc1SHelen Koike sink, RKISP1_RSZ_PAD_SINK, 163e6938cc1SHelen Koike MEDIA_LNK_FL_ENABLED); 164e6938cc1SHelen Koike if (ret) 165e6938cc1SHelen Koike return ret; 166e6938cc1SHelen Koike 167e6938cc1SHelen Koike source = sink; 168e6938cc1SHelen Koike sink = &rkisp1->capture_devs[i].vnode.vdev.entity; 169e6938cc1SHelen Koike ret = media_create_pad_link(source, RKISP1_RSZ_PAD_SRC, 170e6938cc1SHelen Koike sink, 0, flags); 171e6938cc1SHelen Koike if (ret) 172e6938cc1SHelen Koike return ret; 173e6938cc1SHelen Koike } 174e6938cc1SHelen Koike 175e6938cc1SHelen Koike /* params links */ 176e6938cc1SHelen Koike source = &rkisp1->params.vnode.vdev.entity; 177e6938cc1SHelen Koike sink = &rkisp1->isp.sd.entity; 178e6938cc1SHelen Koike ret = media_create_pad_link(source, 0, sink, 179e6938cc1SHelen Koike RKISP1_ISP_PAD_SINK_PARAMS, flags); 180e6938cc1SHelen Koike if (ret) 181e6938cc1SHelen Koike return ret; 182e6938cc1SHelen Koike 183e6938cc1SHelen Koike /* 3A stats links */ 184e6938cc1SHelen Koike source = &rkisp1->isp.sd.entity; 185e6938cc1SHelen Koike sink = &rkisp1->stats.vnode.vdev.entity; 186e6938cc1SHelen Koike return media_create_pad_link(source, RKISP1_ISP_PAD_SOURCE_STATS, 187e6938cc1SHelen Koike sink, 0, flags); 188e6938cc1SHelen Koike } 189e6938cc1SHelen Koike 190e6938cc1SHelen Koike static int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier, 191e6938cc1SHelen Koike struct v4l2_subdev *sd, 192e6938cc1SHelen Koike struct v4l2_async_subdev *asd) 193e6938cc1SHelen Koike { 194e6938cc1SHelen Koike struct rkisp1_device *rkisp1 = 195e6938cc1SHelen Koike container_of(notifier, struct rkisp1_device, notifier); 196e6938cc1SHelen Koike struct rkisp1_sensor_async *s_asd = 197e6938cc1SHelen Koike container_of(asd, struct rkisp1_sensor_async, asd); 198e6938cc1SHelen Koike 199e6938cc1SHelen Koike s_asd->pixel_rate_ctrl = v4l2_ctrl_find(sd->ctrl_handler, 200e6938cc1SHelen Koike V4L2_CID_PIXEL_RATE); 201e6938cc1SHelen Koike s_asd->sd = sd; 202e6938cc1SHelen Koike s_asd->dphy = devm_phy_get(rkisp1->dev, "dphy"); 203e6938cc1SHelen Koike if (IS_ERR(s_asd->dphy)) { 204e6938cc1SHelen Koike if (PTR_ERR(s_asd->dphy) != -EPROBE_DEFER) 205e6938cc1SHelen Koike dev_err(rkisp1->dev, "Couldn't get the MIPI D-PHY\n"); 206e6938cc1SHelen Koike return PTR_ERR(s_asd->dphy); 207e6938cc1SHelen Koike } 208e6938cc1SHelen Koike 209e6938cc1SHelen Koike phy_init(s_asd->dphy); 210e6938cc1SHelen Koike 211e6938cc1SHelen Koike return 0; 212e6938cc1SHelen Koike } 213e6938cc1SHelen Koike 214e6938cc1SHelen Koike static void rkisp1_subdev_notifier_unbind(struct v4l2_async_notifier *notifier, 215e6938cc1SHelen Koike struct v4l2_subdev *sd, 216e6938cc1SHelen Koike struct v4l2_async_subdev *asd) 217e6938cc1SHelen Koike { 218e6938cc1SHelen Koike struct rkisp1_sensor_async *s_asd = 219e6938cc1SHelen Koike container_of(asd, struct rkisp1_sensor_async, asd); 220e6938cc1SHelen Koike 221e6938cc1SHelen Koike phy_exit(s_asd->dphy); 222e6938cc1SHelen Koike } 223e6938cc1SHelen Koike 224e6938cc1SHelen Koike static int rkisp1_subdev_notifier_complete(struct v4l2_async_notifier *notifier) 225e6938cc1SHelen Koike { 226e6938cc1SHelen Koike struct rkisp1_device *rkisp1 = 227e6938cc1SHelen Koike container_of(notifier, struct rkisp1_device, notifier); 228e6938cc1SHelen Koike int ret; 229e6938cc1SHelen Koike 230e6938cc1SHelen Koike ret = rkisp1_create_links(rkisp1); 231e6938cc1SHelen Koike if (ret) 232e6938cc1SHelen Koike return ret; 233e6938cc1SHelen Koike 234e6938cc1SHelen Koike ret = v4l2_device_register_subdev_nodes(&rkisp1->v4l2_dev); 235e6938cc1SHelen Koike if (ret) 236e6938cc1SHelen Koike return ret; 237e6938cc1SHelen Koike 238e6938cc1SHelen Koike dev_dbg(rkisp1->dev, "Async subdev notifier completed\n"); 239e6938cc1SHelen Koike 240e6938cc1SHelen Koike return 0; 241e6938cc1SHelen Koike } 242e6938cc1SHelen Koike 243e6938cc1SHelen Koike static const struct v4l2_async_notifier_operations rkisp1_subdev_notifier_ops = { 244e6938cc1SHelen Koike .bound = rkisp1_subdev_notifier_bound, 245e6938cc1SHelen Koike .unbind = rkisp1_subdev_notifier_unbind, 246e6938cc1SHelen Koike .complete = rkisp1_subdev_notifier_complete, 247e6938cc1SHelen Koike }; 248e6938cc1SHelen Koike 249e6938cc1SHelen Koike static int rkisp1_subdev_notifier(struct rkisp1_device *rkisp1) 250e6938cc1SHelen Koike { 251e6938cc1SHelen Koike struct v4l2_async_notifier *ntf = &rkisp1->notifier; 252e6938cc1SHelen Koike unsigned int next_id = 0; 253e6938cc1SHelen Koike int ret; 254e6938cc1SHelen Koike 2553c8c1539SSakari Ailus v4l2_async_nf_init(ntf); 256e6938cc1SHelen Koike 257e6938cc1SHelen Koike while (1) { 258e6938cc1SHelen Koike struct v4l2_fwnode_endpoint vep = { 259e6938cc1SHelen Koike .bus_type = V4L2_MBUS_CSI2_DPHY 260e6938cc1SHelen Koike }; 261b01edcbdSLaurent Pinchart struct rkisp1_sensor_async *rk_asd; 262e6938cc1SHelen Koike struct fwnode_handle *ep; 263e6938cc1SHelen Koike 264e6938cc1SHelen Koike ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(rkisp1->dev), 265e6938cc1SHelen Koike 0, next_id, 266e6938cc1SHelen Koike FWNODE_GRAPH_ENDPOINT_NEXT); 267e6938cc1SHelen Koike if (!ep) 268e6938cc1SHelen Koike break; 269e6938cc1SHelen Koike 270e6938cc1SHelen Koike ret = v4l2_fwnode_endpoint_parse(ep, &vep); 271e6938cc1SHelen Koike if (ret) 272e6938cc1SHelen Koike goto err_parse; 273e6938cc1SHelen Koike 2743c8c1539SSakari Ailus rk_asd = v4l2_async_nf_add_fwnode_remote(ntf, ep, 2753c8c1539SSakari Ailus struct 2763c8c1539SSakari Ailus rkisp1_sensor_async); 277b01edcbdSLaurent Pinchart if (IS_ERR(rk_asd)) { 278b01edcbdSLaurent Pinchart ret = PTR_ERR(rk_asd); 279e6938cc1SHelen Koike goto err_parse; 280e6938cc1SHelen Koike } 281e6938cc1SHelen Koike 282e6938cc1SHelen Koike rk_asd->mbus_type = vep.bus_type; 283e6938cc1SHelen Koike rk_asd->mbus_flags = vep.bus.mipi_csi2.flags; 284e6938cc1SHelen Koike rk_asd->lanes = vep.bus.mipi_csi2.num_data_lanes; 285e6938cc1SHelen Koike 286e6938cc1SHelen Koike dev_dbg(rkisp1->dev, "registered ep id %d with %d lanes\n", 287e6938cc1SHelen Koike vep.base.id, rk_asd->lanes); 288e6938cc1SHelen Koike 289e6938cc1SHelen Koike next_id = vep.base.id + 1; 290e6938cc1SHelen Koike 291e6938cc1SHelen Koike fwnode_handle_put(ep); 292e6938cc1SHelen Koike 293e6938cc1SHelen Koike continue; 294e6938cc1SHelen Koike err_parse: 295e6938cc1SHelen Koike fwnode_handle_put(ep); 2963c8c1539SSakari Ailus v4l2_async_nf_cleanup(ntf); 297e6938cc1SHelen Koike return ret; 298e6938cc1SHelen Koike } 299e6938cc1SHelen Koike 300e6938cc1SHelen Koike if (next_id == 0) 301e6938cc1SHelen Koike dev_dbg(rkisp1->dev, "no remote subdevice found\n"); 302e6938cc1SHelen Koike ntf->ops = &rkisp1_subdev_notifier_ops; 3033c8c1539SSakari Ailus ret = v4l2_async_nf_register(&rkisp1->v4l2_dev, ntf); 304e6938cc1SHelen Koike if (ret) { 3053c8c1539SSakari Ailus v4l2_async_nf_cleanup(ntf); 306e6938cc1SHelen Koike return ret; 307e6938cc1SHelen Koike } 308e6938cc1SHelen Koike return 0; 309e6938cc1SHelen Koike } 310e6938cc1SHelen Koike 311e6938cc1SHelen Koike /* ---------------------------------------------------------------------------- 312e6938cc1SHelen Koike * Power 313e6938cc1SHelen Koike */ 314e6938cc1SHelen Koike 315e6938cc1SHelen Koike static int __maybe_unused rkisp1_runtime_suspend(struct device *dev) 316e6938cc1SHelen Koike { 317e6938cc1SHelen Koike struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); 318e6938cc1SHelen Koike 319e6938cc1SHelen Koike clk_bulk_disable_unprepare(rkisp1->clk_size, rkisp1->clks); 320e6938cc1SHelen Koike return pinctrl_pm_select_sleep_state(dev); 321e6938cc1SHelen Koike } 322e6938cc1SHelen Koike 323e6938cc1SHelen Koike static int __maybe_unused rkisp1_runtime_resume(struct device *dev) 324e6938cc1SHelen Koike { 325e6938cc1SHelen Koike struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); 326e6938cc1SHelen Koike int ret; 327e6938cc1SHelen Koike 328e6938cc1SHelen Koike ret = pinctrl_pm_select_default_state(dev); 329e6938cc1SHelen Koike if (ret) 330e6938cc1SHelen Koike return ret; 331e6938cc1SHelen Koike ret = clk_bulk_prepare_enable(rkisp1->clk_size, rkisp1->clks); 332e6938cc1SHelen Koike if (ret) 333e6938cc1SHelen Koike return ret; 334e6938cc1SHelen Koike 335e6938cc1SHelen Koike return 0; 336e6938cc1SHelen Koike } 337e6938cc1SHelen Koike 338e6938cc1SHelen Koike static const struct dev_pm_ops rkisp1_pm_ops = { 339e6938cc1SHelen Koike SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 340e6938cc1SHelen Koike pm_runtime_force_resume) 341e6938cc1SHelen Koike SET_RUNTIME_PM_OPS(rkisp1_runtime_suspend, rkisp1_runtime_resume, NULL) 342e6938cc1SHelen Koike }; 343e6938cc1SHelen Koike 344e6938cc1SHelen Koike /* ---------------------------------------------------------------------------- 345e6938cc1SHelen Koike * Core 346e6938cc1SHelen Koike */ 347e6938cc1SHelen Koike 3486ff02276SLaurent Pinchart static void rkisp1_entities_unregister(struct rkisp1_device *rkisp1) 3496ff02276SLaurent Pinchart { 3506ff02276SLaurent Pinchart rkisp1_params_unregister(rkisp1); 3516ff02276SLaurent Pinchart rkisp1_stats_unregister(rkisp1); 3526ff02276SLaurent Pinchart rkisp1_capture_devs_unregister(rkisp1); 3536ff02276SLaurent Pinchart rkisp1_resizer_devs_unregister(rkisp1); 3546ff02276SLaurent Pinchart rkisp1_isp_unregister(rkisp1); 3556ff02276SLaurent Pinchart } 3566ff02276SLaurent Pinchart 357e6938cc1SHelen Koike static int rkisp1_entities_register(struct rkisp1_device *rkisp1) 358e6938cc1SHelen Koike { 359e6938cc1SHelen Koike int ret; 360e6938cc1SHelen Koike 361e6938cc1SHelen Koike ret = rkisp1_isp_register(rkisp1); 362e6938cc1SHelen Koike if (ret) 3636ff02276SLaurent Pinchart goto error; 364e6938cc1SHelen Koike 365e6938cc1SHelen Koike ret = rkisp1_resizer_devs_register(rkisp1); 366e6938cc1SHelen Koike if (ret) 3676ff02276SLaurent Pinchart goto error; 368e6938cc1SHelen Koike 369e6938cc1SHelen Koike ret = rkisp1_capture_devs_register(rkisp1); 370e6938cc1SHelen Koike if (ret) 3716ff02276SLaurent Pinchart goto error; 372e6938cc1SHelen Koike 373e6938cc1SHelen Koike ret = rkisp1_stats_register(rkisp1); 374e6938cc1SHelen Koike if (ret) 3756ff02276SLaurent Pinchart goto error; 376e6938cc1SHelen Koike 377e6938cc1SHelen Koike ret = rkisp1_params_register(rkisp1); 378e6938cc1SHelen Koike if (ret) 3796ff02276SLaurent Pinchart goto error; 380e6938cc1SHelen Koike 381e6938cc1SHelen Koike ret = rkisp1_subdev_notifier(rkisp1); 382e6938cc1SHelen Koike if (ret) { 383e6938cc1SHelen Koike dev_err(rkisp1->dev, 384e6938cc1SHelen Koike "Failed to register subdev notifier(%d)\n", ret); 3856ff02276SLaurent Pinchart goto error; 386e6938cc1SHelen Koike } 387e6938cc1SHelen Koike 388e6938cc1SHelen Koike return 0; 3896ff02276SLaurent Pinchart 3906ff02276SLaurent Pinchart error: 3916ff02276SLaurent Pinchart rkisp1_entities_unregister(rkisp1); 392e6938cc1SHelen Koike return ret; 393e6938cc1SHelen Koike } 394e6938cc1SHelen Koike 395e6938cc1SHelen Koike static irqreturn_t rkisp1_isr(int irq, void *ctx) 396e6938cc1SHelen Koike { 397e6938cc1SHelen Koike /* 398e6938cc1SHelen Koike * Call rkisp1_capture_isr() first to handle the frame that 399e6938cc1SHelen Koike * potentially completed using the current frame_sequence number before 400e6938cc1SHelen Koike * it is potentially incremented by rkisp1_isp_isr() in the vertical 401e6938cc1SHelen Koike * sync. 402e6938cc1SHelen Koike */ 40308818e6aSHeiko Stuebner rkisp1_capture_isr(irq, ctx); 40408818e6aSHeiko Stuebner rkisp1_isp_isr(irq, ctx); 40508818e6aSHeiko Stuebner rkisp1_mipi_isr(irq, ctx); 406e6938cc1SHelen Koike 407e6938cc1SHelen Koike return IRQ_HANDLED; 408e6938cc1SHelen Koike } 409e6938cc1SHelen Koike 410ecf8d36fSHeiko Stuebner static const char * const px30_isp_clks[] = { 411ecf8d36fSHeiko Stuebner "isp", 412ecf8d36fSHeiko Stuebner "aclk", 413ecf8d36fSHeiko Stuebner "hclk", 414ecf8d36fSHeiko Stuebner "pclk", 415ecf8d36fSHeiko Stuebner }; 416ecf8d36fSHeiko Stuebner 417ecf8d36fSHeiko Stuebner static const struct rkisp1_isr_data px30_isp_isrs[] = { 418ecf8d36fSHeiko Stuebner { "isp", rkisp1_isp_isr }, 419ecf8d36fSHeiko Stuebner { "mi", rkisp1_capture_isr }, 420ecf8d36fSHeiko Stuebner { "mipi", rkisp1_mipi_isr }, 421ecf8d36fSHeiko Stuebner }; 422ecf8d36fSHeiko Stuebner 423ecf8d36fSHeiko Stuebner static const struct rkisp1_match_data px30_isp_match_data = { 424ecf8d36fSHeiko Stuebner .clks = px30_isp_clks, 425ecf8d36fSHeiko Stuebner .clk_size = ARRAY_SIZE(px30_isp_clks), 426ecf8d36fSHeiko Stuebner .isrs = px30_isp_isrs, 427ecf8d36fSHeiko Stuebner .isr_size = ARRAY_SIZE(px30_isp_isrs), 428ecf8d36fSHeiko Stuebner .isp_ver = RKISP1_V12, 429ecf8d36fSHeiko Stuebner }; 430ecf8d36fSHeiko Stuebner 431e6938cc1SHelen Koike static const char * const rk3399_isp_clks[] = { 432e6938cc1SHelen Koike "isp", 433e6938cc1SHelen Koike "aclk", 434e6938cc1SHelen Koike "hclk", 435e6938cc1SHelen Koike }; 436e6938cc1SHelen Koike 43708818e6aSHeiko Stuebner static const struct rkisp1_isr_data rk3399_isp_isrs[] = { 43808818e6aSHeiko Stuebner { NULL, rkisp1_isr }, 43908818e6aSHeiko Stuebner }; 44008818e6aSHeiko Stuebner 441fc672d80SHeiko Stuebner static const struct rkisp1_match_data rk3399_isp_match_data = { 442e6938cc1SHelen Koike .clks = rk3399_isp_clks, 44308818e6aSHeiko Stuebner .clk_size = ARRAY_SIZE(rk3399_isp_clks), 44408818e6aSHeiko Stuebner .isrs = rk3399_isp_isrs, 44508818e6aSHeiko Stuebner .isr_size = ARRAY_SIZE(rk3399_isp_isrs), 446fc672d80SHeiko Stuebner .isp_ver = RKISP1_V10, 447e6938cc1SHelen Koike }; 448e6938cc1SHelen Koike 449e6938cc1SHelen Koike static const struct of_device_id rkisp1_of_match[] = { 450e6938cc1SHelen Koike { 451ecf8d36fSHeiko Stuebner .compatible = "rockchip,px30-cif-isp", 452ecf8d36fSHeiko Stuebner .data = &px30_isp_match_data, 453ecf8d36fSHeiko Stuebner }, 454ecf8d36fSHeiko Stuebner { 455e6938cc1SHelen Koike .compatible = "rockchip,rk3399-cif-isp", 456fc672d80SHeiko Stuebner .data = &rk3399_isp_match_data, 457e6938cc1SHelen Koike }, 458e6938cc1SHelen Koike {}, 459e6938cc1SHelen Koike }; 460e6938cc1SHelen Koike MODULE_DEVICE_TABLE(of, rkisp1_of_match); 461e6938cc1SHelen Koike 462e6938cc1SHelen Koike static int rkisp1_probe(struct platform_device *pdev) 463e6938cc1SHelen Koike { 464fc672d80SHeiko Stuebner const struct rkisp1_match_data *match_data; 465e6938cc1SHelen Koike struct device *dev = &pdev->dev; 466e6938cc1SHelen Koike struct rkisp1_device *rkisp1; 467e6938cc1SHelen Koike struct v4l2_device *v4l2_dev; 468e6938cc1SHelen Koike unsigned int i; 469e6938cc1SHelen Koike int ret, irq; 470e6938cc1SHelen Koike 471fc672d80SHeiko Stuebner match_data = of_device_get_match_data(&pdev->dev); 472fc672d80SHeiko Stuebner if (!match_data) 473e6938cc1SHelen Koike return -ENODEV; 474e6938cc1SHelen Koike 475e6938cc1SHelen Koike rkisp1 = devm_kzalloc(dev, sizeof(*rkisp1), GFP_KERNEL); 476e6938cc1SHelen Koike if (!rkisp1) 477e6938cc1SHelen Koike return -ENOMEM; 478e6938cc1SHelen Koike 479e6938cc1SHelen Koike dev_set_drvdata(dev, rkisp1); 480e6938cc1SHelen Koike rkisp1->dev = dev; 481e6938cc1SHelen Koike 482e6938cc1SHelen Koike mutex_init(&rkisp1->stream_lock); 483e6938cc1SHelen Koike 484e6938cc1SHelen Koike rkisp1->base_addr = devm_platform_ioremap_resource(pdev, 0); 485e6938cc1SHelen Koike if (IS_ERR(rkisp1->base_addr)) 486e6938cc1SHelen Koike return PTR_ERR(rkisp1->base_addr); 487e6938cc1SHelen Koike 48808818e6aSHeiko Stuebner for (i = 0; i < match_data->isr_size; i++) { 489*fd83ef8fSLaurent Pinchart irq = match_data->isrs[i].name 490*fd83ef8fSLaurent Pinchart ? platform_get_irq_byname(pdev, match_data->isrs[i].name) 491*fd83ef8fSLaurent Pinchart : platform_get_irq(pdev, i); 492e6938cc1SHelen Koike if (irq < 0) 493e6938cc1SHelen Koike return irq; 494e6938cc1SHelen Koike 49508818e6aSHeiko Stuebner ret = devm_request_irq(dev, irq, match_data->isrs[i].isr, IRQF_SHARED, 496e6938cc1SHelen Koike dev_driver_string(dev), dev); 497e6938cc1SHelen Koike if (ret) { 498e6938cc1SHelen Koike dev_err(dev, "request irq failed: %d\n", ret); 499e6938cc1SHelen Koike return ret; 500e6938cc1SHelen Koike } 50108818e6aSHeiko Stuebner } 502e6938cc1SHelen Koike 50308818e6aSHeiko Stuebner for (i = 0; i < match_data->clk_size; i++) 504fc672d80SHeiko Stuebner rkisp1->clks[i].id = match_data->clks[i]; 50508818e6aSHeiko Stuebner ret = devm_clk_bulk_get(dev, match_data->clk_size, rkisp1->clks); 506e6938cc1SHelen Koike if (ret) 507e6938cc1SHelen Koike return ret; 50808818e6aSHeiko Stuebner rkisp1->clk_size = match_data->clk_size; 509e6938cc1SHelen Koike 510e6938cc1SHelen Koike pm_runtime_enable(&pdev->dev); 511e6938cc1SHelen Koike 512fc672d80SHeiko Stuebner rkisp1->media_dev.hw_revision = match_data->isp_ver; 513e6938cc1SHelen Koike strscpy(rkisp1->media_dev.model, RKISP1_DRIVER_NAME, 514e6938cc1SHelen Koike sizeof(rkisp1->media_dev.model)); 515e6938cc1SHelen Koike rkisp1->media_dev.dev = &pdev->dev; 516e6938cc1SHelen Koike strscpy(rkisp1->media_dev.bus_info, RKISP1_BUS_INFO, 517e6938cc1SHelen Koike sizeof(rkisp1->media_dev.bus_info)); 518e6938cc1SHelen Koike media_device_init(&rkisp1->media_dev); 519e6938cc1SHelen Koike 520e6938cc1SHelen Koike v4l2_dev = &rkisp1->v4l2_dev; 521e6938cc1SHelen Koike v4l2_dev->mdev = &rkisp1->media_dev; 522e6938cc1SHelen Koike strscpy(v4l2_dev->name, RKISP1_DRIVER_NAME, sizeof(v4l2_dev->name)); 523e6938cc1SHelen Koike 524e6938cc1SHelen Koike ret = v4l2_device_register(rkisp1->dev, &rkisp1->v4l2_dev); 525e6938cc1SHelen Koike if (ret) 526e6938cc1SHelen Koike return ret; 527e6938cc1SHelen Koike 528e6938cc1SHelen Koike ret = media_device_register(&rkisp1->media_dev); 529e6938cc1SHelen Koike if (ret) { 530e6938cc1SHelen Koike dev_err(dev, "Failed to register media device: %d\n", ret); 531e6938cc1SHelen Koike goto err_unreg_v4l2_dev; 532e6938cc1SHelen Koike } 533e6938cc1SHelen Koike 534e6938cc1SHelen Koike ret = rkisp1_entities_register(rkisp1); 535e6938cc1SHelen Koike if (ret) 536e6938cc1SHelen Koike goto err_unreg_media_dev; 537e6938cc1SHelen Koike 538e6938cc1SHelen Koike rkisp1_debug_init(rkisp1); 539e6938cc1SHelen Koike 540e6938cc1SHelen Koike return 0; 541e6938cc1SHelen Koike 542e6938cc1SHelen Koike err_unreg_media_dev: 543e6938cc1SHelen Koike media_device_unregister(&rkisp1->media_dev); 544e6938cc1SHelen Koike err_unreg_v4l2_dev: 545e6938cc1SHelen Koike v4l2_device_unregister(&rkisp1->v4l2_dev); 546e6938cc1SHelen Koike pm_runtime_disable(&pdev->dev); 547e6938cc1SHelen Koike return ret; 548e6938cc1SHelen Koike } 549e6938cc1SHelen Koike 550e6938cc1SHelen Koike static int rkisp1_remove(struct platform_device *pdev) 551e6938cc1SHelen Koike { 552e6938cc1SHelen Koike struct rkisp1_device *rkisp1 = platform_get_drvdata(pdev); 553e6938cc1SHelen Koike 5543c8c1539SSakari Ailus v4l2_async_nf_unregister(&rkisp1->notifier); 5553c8c1539SSakari Ailus v4l2_async_nf_cleanup(&rkisp1->notifier); 556e6938cc1SHelen Koike 5576ff02276SLaurent Pinchart rkisp1_entities_unregister(rkisp1); 5588682037dSLaurent Pinchart rkisp1_debug_cleanup(rkisp1); 559e6938cc1SHelen Koike 560e6938cc1SHelen Koike media_device_unregister(&rkisp1->media_dev); 561e6938cc1SHelen Koike v4l2_device_unregister(&rkisp1->v4l2_dev); 562e6938cc1SHelen Koike 563e6938cc1SHelen Koike pm_runtime_disable(&pdev->dev); 564e6938cc1SHelen Koike 565e6938cc1SHelen Koike return 0; 566e6938cc1SHelen Koike } 567e6938cc1SHelen Koike 568e6938cc1SHelen Koike static struct platform_driver rkisp1_drv = { 569e6938cc1SHelen Koike .driver = { 570e6938cc1SHelen Koike .name = RKISP1_DRIVER_NAME, 571e6938cc1SHelen Koike .of_match_table = of_match_ptr(rkisp1_of_match), 572e6938cc1SHelen Koike .pm = &rkisp1_pm_ops, 573e6938cc1SHelen Koike }, 574e6938cc1SHelen Koike .probe = rkisp1_probe, 575e6938cc1SHelen Koike .remove = rkisp1_remove, 576e6938cc1SHelen Koike }; 577e6938cc1SHelen Koike 578e6938cc1SHelen Koike module_platform_driver(rkisp1_drv); 579e6938cc1SHelen Koike MODULE_DESCRIPTION("Rockchip ISP1 platform driver"); 580e6938cc1SHelen Koike MODULE_LICENSE("Dual MIT/GPL"); 581