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 /* ---------------------------------------------------------------------------- 109e6938cc1SHelen Koike * Sensor DT bindings 110e6938cc1SHelen Koike */ 111e6938cc1SHelen Koike 112e6938cc1SHelen Koike static int rkisp1_create_links(struct rkisp1_device *rkisp1) 113e6938cc1SHelen Koike { 114e6938cc1SHelen Koike struct media_entity *source, *sink; 115e6938cc1SHelen Koike unsigned int flags, source_pad; 116e6938cc1SHelen Koike struct v4l2_subdev *sd; 117e6938cc1SHelen Koike unsigned int i; 118e6938cc1SHelen Koike int ret; 119e6938cc1SHelen Koike 120e6938cc1SHelen Koike /* sensor links */ 121e6938cc1SHelen Koike flags = MEDIA_LNK_FL_ENABLED; 122e6938cc1SHelen Koike list_for_each_entry(sd, &rkisp1->v4l2_dev.subdevs, list) { 123e6938cc1SHelen Koike if (sd == &rkisp1->isp.sd || 124e6938cc1SHelen Koike sd == &rkisp1->resizer_devs[RKISP1_MAINPATH].sd || 125e6938cc1SHelen Koike sd == &rkisp1->resizer_devs[RKISP1_SELFPATH].sd) 126e6938cc1SHelen Koike continue; 127e6938cc1SHelen Koike 128e6938cc1SHelen Koike ret = media_entity_get_fwnode_pad(&sd->entity, sd->fwnode, 129e6938cc1SHelen Koike MEDIA_PAD_FL_SOURCE); 130e6938cc1SHelen Koike if (ret < 0) { 131e6938cc1SHelen Koike dev_err(rkisp1->dev, "failed to find src pad for %s\n", 132e6938cc1SHelen Koike sd->name); 133e6938cc1SHelen Koike return ret; 134e6938cc1SHelen Koike } 135e6938cc1SHelen Koike source_pad = ret; 136e6938cc1SHelen Koike 137e6938cc1SHelen Koike ret = media_create_pad_link(&sd->entity, source_pad, 138e6938cc1SHelen Koike &rkisp1->isp.sd.entity, 139e6938cc1SHelen Koike RKISP1_ISP_PAD_SINK_VIDEO, 140e6938cc1SHelen Koike flags); 141e6938cc1SHelen Koike if (ret) 142e6938cc1SHelen Koike return ret; 143e6938cc1SHelen Koike 144e6938cc1SHelen Koike flags = 0; 145e6938cc1SHelen Koike } 146e6938cc1SHelen Koike 147e6938cc1SHelen Koike flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE; 148e6938cc1SHelen Koike 149e6938cc1SHelen Koike /* create ISP->RSZ->CAP links */ 150e6938cc1SHelen Koike for (i = 0; i < 2; i++) { 151e6938cc1SHelen Koike source = &rkisp1->isp.sd.entity; 152e6938cc1SHelen Koike sink = &rkisp1->resizer_devs[i].sd.entity; 153e6938cc1SHelen Koike ret = media_create_pad_link(source, RKISP1_ISP_PAD_SOURCE_VIDEO, 154e6938cc1SHelen Koike sink, RKISP1_RSZ_PAD_SINK, 155e6938cc1SHelen Koike MEDIA_LNK_FL_ENABLED); 156e6938cc1SHelen Koike if (ret) 157e6938cc1SHelen Koike return ret; 158e6938cc1SHelen Koike 159e6938cc1SHelen Koike source = sink; 160e6938cc1SHelen Koike sink = &rkisp1->capture_devs[i].vnode.vdev.entity; 161e6938cc1SHelen Koike ret = media_create_pad_link(source, RKISP1_RSZ_PAD_SRC, 162e6938cc1SHelen Koike sink, 0, flags); 163e6938cc1SHelen Koike if (ret) 164e6938cc1SHelen Koike return ret; 165e6938cc1SHelen Koike } 166e6938cc1SHelen Koike 167e6938cc1SHelen Koike /* params links */ 168e6938cc1SHelen Koike source = &rkisp1->params.vnode.vdev.entity; 169e6938cc1SHelen Koike sink = &rkisp1->isp.sd.entity; 170e6938cc1SHelen Koike ret = media_create_pad_link(source, 0, sink, 171e6938cc1SHelen Koike RKISP1_ISP_PAD_SINK_PARAMS, flags); 172e6938cc1SHelen Koike if (ret) 173e6938cc1SHelen Koike return ret; 174e6938cc1SHelen Koike 175e6938cc1SHelen Koike /* 3A stats links */ 176e6938cc1SHelen Koike source = &rkisp1->isp.sd.entity; 177e6938cc1SHelen Koike sink = &rkisp1->stats.vnode.vdev.entity; 178e6938cc1SHelen Koike return media_create_pad_link(source, RKISP1_ISP_PAD_SOURCE_STATS, 179e6938cc1SHelen Koike sink, 0, flags); 180e6938cc1SHelen Koike } 181e6938cc1SHelen Koike 182e6938cc1SHelen Koike static int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier, 183e6938cc1SHelen Koike struct v4l2_subdev *sd, 184e6938cc1SHelen Koike struct v4l2_async_subdev *asd) 185e6938cc1SHelen Koike { 186e6938cc1SHelen Koike struct rkisp1_device *rkisp1 = 187e6938cc1SHelen Koike container_of(notifier, struct rkisp1_device, notifier); 188e6938cc1SHelen Koike struct rkisp1_sensor_async *s_asd = 189e6938cc1SHelen Koike container_of(asd, struct rkisp1_sensor_async, asd); 190e6938cc1SHelen Koike 191e6938cc1SHelen Koike s_asd->pixel_rate_ctrl = v4l2_ctrl_find(sd->ctrl_handler, 192e6938cc1SHelen Koike V4L2_CID_PIXEL_RATE); 193*af2dababSLaurent Pinchart if (!s_asd->pixel_rate_ctrl) { 194*af2dababSLaurent Pinchart dev_err(rkisp1->dev, "No pixel rate control in subdev %s\n", 195*af2dababSLaurent Pinchart sd->name); 196*af2dababSLaurent Pinchart return -EINVAL; 197*af2dababSLaurent Pinchart } 198*af2dababSLaurent Pinchart 199e6938cc1SHelen Koike s_asd->sd = sd; 200e6938cc1SHelen Koike s_asd->dphy = devm_phy_get(rkisp1->dev, "dphy"); 201e6938cc1SHelen Koike if (IS_ERR(s_asd->dphy)) { 202e6938cc1SHelen Koike if (PTR_ERR(s_asd->dphy) != -EPROBE_DEFER) 203e6938cc1SHelen Koike dev_err(rkisp1->dev, "Couldn't get the MIPI D-PHY\n"); 204e6938cc1SHelen Koike return PTR_ERR(s_asd->dphy); 205e6938cc1SHelen Koike } 206e6938cc1SHelen Koike 207e6938cc1SHelen Koike phy_init(s_asd->dphy); 208e6938cc1SHelen Koike 209e6938cc1SHelen Koike return 0; 210e6938cc1SHelen Koike } 211e6938cc1SHelen Koike 212e6938cc1SHelen Koike static void rkisp1_subdev_notifier_unbind(struct v4l2_async_notifier *notifier, 213e6938cc1SHelen Koike struct v4l2_subdev *sd, 214e6938cc1SHelen Koike struct v4l2_async_subdev *asd) 215e6938cc1SHelen Koike { 216e6938cc1SHelen Koike struct rkisp1_sensor_async *s_asd = 217e6938cc1SHelen Koike container_of(asd, struct rkisp1_sensor_async, asd); 218e6938cc1SHelen Koike 219e6938cc1SHelen Koike phy_exit(s_asd->dphy); 220e6938cc1SHelen Koike } 221e6938cc1SHelen Koike 222e6938cc1SHelen Koike static int rkisp1_subdev_notifier_complete(struct v4l2_async_notifier *notifier) 223e6938cc1SHelen Koike { 224e6938cc1SHelen Koike struct rkisp1_device *rkisp1 = 225e6938cc1SHelen Koike container_of(notifier, struct rkisp1_device, notifier); 226e6938cc1SHelen Koike int ret; 227e6938cc1SHelen Koike 228e6938cc1SHelen Koike ret = rkisp1_create_links(rkisp1); 229e6938cc1SHelen Koike if (ret) 230e6938cc1SHelen Koike return ret; 231e6938cc1SHelen Koike 232e6938cc1SHelen Koike ret = v4l2_device_register_subdev_nodes(&rkisp1->v4l2_dev); 233e6938cc1SHelen Koike if (ret) 234e6938cc1SHelen Koike return ret; 235e6938cc1SHelen Koike 236e6938cc1SHelen Koike dev_dbg(rkisp1->dev, "Async subdev notifier completed\n"); 237e6938cc1SHelen Koike 238e6938cc1SHelen Koike return 0; 239e6938cc1SHelen Koike } 240e6938cc1SHelen Koike 241e6938cc1SHelen Koike static const struct v4l2_async_notifier_operations rkisp1_subdev_notifier_ops = { 242e6938cc1SHelen Koike .bound = rkisp1_subdev_notifier_bound, 243e6938cc1SHelen Koike .unbind = rkisp1_subdev_notifier_unbind, 244e6938cc1SHelen Koike .complete = rkisp1_subdev_notifier_complete, 245e6938cc1SHelen Koike }; 246e6938cc1SHelen Koike 247e6938cc1SHelen Koike static int rkisp1_subdev_notifier(struct rkisp1_device *rkisp1) 248e6938cc1SHelen Koike { 249e6938cc1SHelen Koike struct v4l2_async_notifier *ntf = &rkisp1->notifier; 250e6938cc1SHelen Koike unsigned int next_id = 0; 251e6938cc1SHelen Koike int ret; 252e6938cc1SHelen Koike 2533c8c1539SSakari Ailus v4l2_async_nf_init(ntf); 254e6938cc1SHelen Koike 255e6938cc1SHelen Koike while (1) { 256e6938cc1SHelen Koike struct v4l2_fwnode_endpoint vep = { 257e6938cc1SHelen Koike .bus_type = V4L2_MBUS_CSI2_DPHY 258e6938cc1SHelen Koike }; 259b01edcbdSLaurent Pinchart struct rkisp1_sensor_async *rk_asd; 260e6938cc1SHelen Koike struct fwnode_handle *ep; 261e6938cc1SHelen Koike 262e6938cc1SHelen Koike ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(rkisp1->dev), 263e6938cc1SHelen Koike 0, next_id, 264e6938cc1SHelen Koike FWNODE_GRAPH_ENDPOINT_NEXT); 265e6938cc1SHelen Koike if (!ep) 266e6938cc1SHelen Koike break; 267e6938cc1SHelen Koike 268e6938cc1SHelen Koike ret = v4l2_fwnode_endpoint_parse(ep, &vep); 269e6938cc1SHelen Koike if (ret) 270e6938cc1SHelen Koike goto err_parse; 271e6938cc1SHelen Koike 2723c8c1539SSakari Ailus rk_asd = v4l2_async_nf_add_fwnode_remote(ntf, ep, 2733c8c1539SSakari Ailus struct 2743c8c1539SSakari Ailus rkisp1_sensor_async); 275b01edcbdSLaurent Pinchart if (IS_ERR(rk_asd)) { 276b01edcbdSLaurent Pinchart ret = PTR_ERR(rk_asd); 277e6938cc1SHelen Koike goto err_parse; 278e6938cc1SHelen Koike } 279e6938cc1SHelen Koike 280e6938cc1SHelen Koike rk_asd->mbus_type = vep.bus_type; 281e6938cc1SHelen Koike rk_asd->mbus_flags = vep.bus.mipi_csi2.flags; 282e6938cc1SHelen Koike rk_asd->lanes = vep.bus.mipi_csi2.num_data_lanes; 283e6938cc1SHelen Koike 284e6938cc1SHelen Koike dev_dbg(rkisp1->dev, "registered ep id %d with %d lanes\n", 285e6938cc1SHelen Koike vep.base.id, rk_asd->lanes); 286e6938cc1SHelen Koike 287e6938cc1SHelen Koike next_id = vep.base.id + 1; 288e6938cc1SHelen Koike 289e6938cc1SHelen Koike fwnode_handle_put(ep); 290e6938cc1SHelen Koike 291e6938cc1SHelen Koike continue; 292e6938cc1SHelen Koike err_parse: 293e6938cc1SHelen Koike fwnode_handle_put(ep); 2943c8c1539SSakari Ailus v4l2_async_nf_cleanup(ntf); 295e6938cc1SHelen Koike return ret; 296e6938cc1SHelen Koike } 297e6938cc1SHelen Koike 298e6938cc1SHelen Koike if (next_id == 0) 299e6938cc1SHelen Koike dev_dbg(rkisp1->dev, "no remote subdevice found\n"); 300e6938cc1SHelen Koike ntf->ops = &rkisp1_subdev_notifier_ops; 3013c8c1539SSakari Ailus ret = v4l2_async_nf_register(&rkisp1->v4l2_dev, ntf); 302e6938cc1SHelen Koike if (ret) { 3033c8c1539SSakari Ailus v4l2_async_nf_cleanup(ntf); 304e6938cc1SHelen Koike return ret; 305e6938cc1SHelen Koike } 306e6938cc1SHelen Koike return 0; 307e6938cc1SHelen Koike } 308e6938cc1SHelen Koike 309e6938cc1SHelen Koike /* ---------------------------------------------------------------------------- 310e6938cc1SHelen Koike * Power 311e6938cc1SHelen Koike */ 312e6938cc1SHelen Koike 313e6938cc1SHelen Koike static int __maybe_unused rkisp1_runtime_suspend(struct device *dev) 314e6938cc1SHelen Koike { 315e6938cc1SHelen Koike struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); 316e6938cc1SHelen Koike 317e6938cc1SHelen Koike clk_bulk_disable_unprepare(rkisp1->clk_size, rkisp1->clks); 318e6938cc1SHelen Koike return pinctrl_pm_select_sleep_state(dev); 319e6938cc1SHelen Koike } 320e6938cc1SHelen Koike 321e6938cc1SHelen Koike static int __maybe_unused rkisp1_runtime_resume(struct device *dev) 322e6938cc1SHelen Koike { 323e6938cc1SHelen Koike struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); 324e6938cc1SHelen Koike int ret; 325e6938cc1SHelen Koike 326e6938cc1SHelen Koike ret = pinctrl_pm_select_default_state(dev); 327e6938cc1SHelen Koike if (ret) 328e6938cc1SHelen Koike return ret; 329e6938cc1SHelen Koike ret = clk_bulk_prepare_enable(rkisp1->clk_size, rkisp1->clks); 330e6938cc1SHelen Koike if (ret) 331e6938cc1SHelen Koike return ret; 332e6938cc1SHelen Koike 333e6938cc1SHelen Koike return 0; 334e6938cc1SHelen Koike } 335e6938cc1SHelen Koike 336e6938cc1SHelen Koike static const struct dev_pm_ops rkisp1_pm_ops = { 337e6938cc1SHelen Koike SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 338e6938cc1SHelen Koike pm_runtime_force_resume) 339e6938cc1SHelen Koike SET_RUNTIME_PM_OPS(rkisp1_runtime_suspend, rkisp1_runtime_resume, NULL) 340e6938cc1SHelen Koike }; 341e6938cc1SHelen Koike 342e6938cc1SHelen Koike /* ---------------------------------------------------------------------------- 343e6938cc1SHelen Koike * Core 344e6938cc1SHelen Koike */ 345e6938cc1SHelen Koike 3466ff02276SLaurent Pinchart static void rkisp1_entities_unregister(struct rkisp1_device *rkisp1) 3476ff02276SLaurent Pinchart { 3486ff02276SLaurent Pinchart rkisp1_params_unregister(rkisp1); 3496ff02276SLaurent Pinchart rkisp1_stats_unregister(rkisp1); 3506ff02276SLaurent Pinchart rkisp1_capture_devs_unregister(rkisp1); 3516ff02276SLaurent Pinchart rkisp1_resizer_devs_unregister(rkisp1); 3526ff02276SLaurent Pinchart rkisp1_isp_unregister(rkisp1); 3536ff02276SLaurent Pinchart } 3546ff02276SLaurent Pinchart 355e6938cc1SHelen Koike static int rkisp1_entities_register(struct rkisp1_device *rkisp1) 356e6938cc1SHelen Koike { 357e6938cc1SHelen Koike int ret; 358e6938cc1SHelen Koike 359e6938cc1SHelen Koike ret = rkisp1_isp_register(rkisp1); 360e6938cc1SHelen Koike if (ret) 3616ff02276SLaurent Pinchart goto error; 362e6938cc1SHelen Koike 363e6938cc1SHelen Koike ret = rkisp1_resizer_devs_register(rkisp1); 364e6938cc1SHelen Koike if (ret) 3656ff02276SLaurent Pinchart goto error; 366e6938cc1SHelen Koike 367e6938cc1SHelen Koike ret = rkisp1_capture_devs_register(rkisp1); 368e6938cc1SHelen Koike if (ret) 3696ff02276SLaurent Pinchart goto error; 370e6938cc1SHelen Koike 371e6938cc1SHelen Koike ret = rkisp1_stats_register(rkisp1); 372e6938cc1SHelen Koike if (ret) 3736ff02276SLaurent Pinchart goto error; 374e6938cc1SHelen Koike 375e6938cc1SHelen Koike ret = rkisp1_params_register(rkisp1); 376e6938cc1SHelen Koike if (ret) 3776ff02276SLaurent Pinchart goto error; 378e6938cc1SHelen Koike 379e6938cc1SHelen Koike ret = rkisp1_subdev_notifier(rkisp1); 380e6938cc1SHelen Koike if (ret) { 381e6938cc1SHelen Koike dev_err(rkisp1->dev, 382e6938cc1SHelen Koike "Failed to register subdev notifier(%d)\n", ret); 3836ff02276SLaurent Pinchart goto error; 384e6938cc1SHelen Koike } 385e6938cc1SHelen Koike 386e6938cc1SHelen Koike return 0; 3876ff02276SLaurent Pinchart 3886ff02276SLaurent Pinchart error: 3896ff02276SLaurent Pinchart rkisp1_entities_unregister(rkisp1); 390e6938cc1SHelen Koike return ret; 391e6938cc1SHelen Koike } 392e6938cc1SHelen Koike 393e6938cc1SHelen Koike static irqreturn_t rkisp1_isr(int irq, void *ctx) 394e6938cc1SHelen Koike { 395e6938cc1SHelen Koike /* 396e6938cc1SHelen Koike * Call rkisp1_capture_isr() first to handle the frame that 397e6938cc1SHelen Koike * potentially completed using the current frame_sequence number before 398e6938cc1SHelen Koike * it is potentially incremented by rkisp1_isp_isr() in the vertical 399e6938cc1SHelen Koike * sync. 400e6938cc1SHelen Koike */ 40108818e6aSHeiko Stuebner rkisp1_capture_isr(irq, ctx); 40208818e6aSHeiko Stuebner rkisp1_isp_isr(irq, ctx); 40308818e6aSHeiko Stuebner rkisp1_mipi_isr(irq, ctx); 404e6938cc1SHelen Koike 405e6938cc1SHelen Koike return IRQ_HANDLED; 406e6938cc1SHelen Koike } 407e6938cc1SHelen Koike 408ecf8d36fSHeiko Stuebner static const char * const px30_isp_clks[] = { 409ecf8d36fSHeiko Stuebner "isp", 410ecf8d36fSHeiko Stuebner "aclk", 411ecf8d36fSHeiko Stuebner "hclk", 412ecf8d36fSHeiko Stuebner "pclk", 413ecf8d36fSHeiko Stuebner }; 414ecf8d36fSHeiko Stuebner 415ecf8d36fSHeiko Stuebner static const struct rkisp1_isr_data px30_isp_isrs[] = { 416ecf8d36fSHeiko Stuebner { "isp", rkisp1_isp_isr }, 417ecf8d36fSHeiko Stuebner { "mi", rkisp1_capture_isr }, 418ecf8d36fSHeiko Stuebner { "mipi", rkisp1_mipi_isr }, 419ecf8d36fSHeiko Stuebner }; 420ecf8d36fSHeiko Stuebner 421cdce5b95SLaurent Pinchart static const struct rkisp1_info px30_isp_info = { 422ecf8d36fSHeiko Stuebner .clks = px30_isp_clks, 423ecf8d36fSHeiko Stuebner .clk_size = ARRAY_SIZE(px30_isp_clks), 424ecf8d36fSHeiko Stuebner .isrs = px30_isp_isrs, 425ecf8d36fSHeiko Stuebner .isr_size = ARRAY_SIZE(px30_isp_isrs), 426ecf8d36fSHeiko Stuebner .isp_ver = RKISP1_V12, 427ecf8d36fSHeiko Stuebner }; 428ecf8d36fSHeiko Stuebner 429e6938cc1SHelen Koike static const char * const rk3399_isp_clks[] = { 430e6938cc1SHelen Koike "isp", 431e6938cc1SHelen Koike "aclk", 432e6938cc1SHelen Koike "hclk", 433e6938cc1SHelen Koike }; 434e6938cc1SHelen Koike 43508818e6aSHeiko Stuebner static const struct rkisp1_isr_data rk3399_isp_isrs[] = { 43608818e6aSHeiko Stuebner { NULL, rkisp1_isr }, 43708818e6aSHeiko Stuebner }; 43808818e6aSHeiko Stuebner 439cdce5b95SLaurent Pinchart static const struct rkisp1_info rk3399_isp_info = { 440e6938cc1SHelen Koike .clks = rk3399_isp_clks, 44108818e6aSHeiko Stuebner .clk_size = ARRAY_SIZE(rk3399_isp_clks), 44208818e6aSHeiko Stuebner .isrs = rk3399_isp_isrs, 44308818e6aSHeiko Stuebner .isr_size = ARRAY_SIZE(rk3399_isp_isrs), 444fc672d80SHeiko Stuebner .isp_ver = RKISP1_V10, 445e6938cc1SHelen Koike }; 446e6938cc1SHelen Koike 447e6938cc1SHelen Koike static const struct of_device_id rkisp1_of_match[] = { 448e6938cc1SHelen Koike { 449ecf8d36fSHeiko Stuebner .compatible = "rockchip,px30-cif-isp", 450cdce5b95SLaurent Pinchart .data = &px30_isp_info, 451ecf8d36fSHeiko Stuebner }, 452ecf8d36fSHeiko Stuebner { 453e6938cc1SHelen Koike .compatible = "rockchip,rk3399-cif-isp", 454cdce5b95SLaurent Pinchart .data = &rk3399_isp_info, 455e6938cc1SHelen Koike }, 456e6938cc1SHelen Koike {}, 457e6938cc1SHelen Koike }; 458e6938cc1SHelen Koike MODULE_DEVICE_TABLE(of, rkisp1_of_match); 459e6938cc1SHelen Koike 460e6938cc1SHelen Koike static int rkisp1_probe(struct platform_device *pdev) 461e6938cc1SHelen Koike { 462cdce5b95SLaurent Pinchart const struct rkisp1_info *info; 463e6938cc1SHelen Koike struct device *dev = &pdev->dev; 464e6938cc1SHelen Koike struct rkisp1_device *rkisp1; 465e6938cc1SHelen Koike struct v4l2_device *v4l2_dev; 466e6938cc1SHelen Koike unsigned int i; 467e6938cc1SHelen Koike int ret, irq; 468196179c5SLaurent Pinchart u32 cif_id; 469e6938cc1SHelen Koike 470e6938cc1SHelen Koike rkisp1 = devm_kzalloc(dev, sizeof(*rkisp1), GFP_KERNEL); 471e6938cc1SHelen Koike if (!rkisp1) 472e6938cc1SHelen Koike return -ENOMEM; 473e6938cc1SHelen Koike 4749125aee7SPaul Elder info = of_device_get_match_data(dev); 4759125aee7SPaul Elder rkisp1->info = info; 4769125aee7SPaul Elder 477e6938cc1SHelen Koike dev_set_drvdata(dev, rkisp1); 478e6938cc1SHelen Koike rkisp1->dev = dev; 479e6938cc1SHelen Koike 480e6938cc1SHelen Koike mutex_init(&rkisp1->stream_lock); 481e6938cc1SHelen Koike 482e6938cc1SHelen Koike rkisp1->base_addr = devm_platform_ioremap_resource(pdev, 0); 483e6938cc1SHelen Koike if (IS_ERR(rkisp1->base_addr)) 484e6938cc1SHelen Koike return PTR_ERR(rkisp1->base_addr); 485e6938cc1SHelen Koike 486cdce5b95SLaurent Pinchart for (i = 0; i < info->isr_size; i++) { 487cdce5b95SLaurent Pinchart irq = info->isrs[i].name 488cdce5b95SLaurent Pinchart ? platform_get_irq_byname(pdev, info->isrs[i].name) 489fd83ef8fSLaurent Pinchart : platform_get_irq(pdev, i); 490e6938cc1SHelen Koike if (irq < 0) 491e6938cc1SHelen Koike return irq; 492e6938cc1SHelen Koike 493cdce5b95SLaurent Pinchart ret = devm_request_irq(dev, irq, info->isrs[i].isr, IRQF_SHARED, 494e6938cc1SHelen Koike dev_driver_string(dev), dev); 495e6938cc1SHelen Koike if (ret) { 496e6938cc1SHelen Koike dev_err(dev, "request irq failed: %d\n", ret); 497e6938cc1SHelen Koike return ret; 498e6938cc1SHelen Koike } 49908818e6aSHeiko Stuebner } 500e6938cc1SHelen Koike 501cdce5b95SLaurent Pinchart for (i = 0; i < info->clk_size; i++) 502cdce5b95SLaurent Pinchart rkisp1->clks[i].id = info->clks[i]; 503cdce5b95SLaurent Pinchart ret = devm_clk_bulk_get(dev, info->clk_size, rkisp1->clks); 504e6938cc1SHelen Koike if (ret) 505e6938cc1SHelen Koike return ret; 506cdce5b95SLaurent Pinchart rkisp1->clk_size = info->clk_size; 507e6938cc1SHelen Koike 508e6938cc1SHelen Koike pm_runtime_enable(&pdev->dev); 509e6938cc1SHelen Koike 510196179c5SLaurent Pinchart ret = pm_runtime_resume_and_get(&pdev->dev); 511196179c5SLaurent Pinchart if (ret) 512196179c5SLaurent Pinchart goto err_pm_runtime_disable; 513196179c5SLaurent Pinchart 514196179c5SLaurent Pinchart cif_id = rkisp1_read(rkisp1, RKISP1_CIF_VI_ID); 515196179c5SLaurent Pinchart dev_dbg(rkisp1->dev, "CIF_ID 0x%08x\n", cif_id); 516196179c5SLaurent Pinchart 517196179c5SLaurent Pinchart pm_runtime_put(&pdev->dev); 518196179c5SLaurent Pinchart 519cdce5b95SLaurent Pinchart rkisp1->media_dev.hw_revision = info->isp_ver; 520e6938cc1SHelen Koike strscpy(rkisp1->media_dev.model, RKISP1_DRIVER_NAME, 521e6938cc1SHelen Koike sizeof(rkisp1->media_dev.model)); 522e6938cc1SHelen Koike rkisp1->media_dev.dev = &pdev->dev; 523e6938cc1SHelen Koike strscpy(rkisp1->media_dev.bus_info, RKISP1_BUS_INFO, 524e6938cc1SHelen Koike sizeof(rkisp1->media_dev.bus_info)); 525e6938cc1SHelen Koike media_device_init(&rkisp1->media_dev); 526e6938cc1SHelen Koike 527e6938cc1SHelen Koike v4l2_dev = &rkisp1->v4l2_dev; 528e6938cc1SHelen Koike v4l2_dev->mdev = &rkisp1->media_dev; 529e6938cc1SHelen Koike strscpy(v4l2_dev->name, RKISP1_DRIVER_NAME, sizeof(v4l2_dev->name)); 530e6938cc1SHelen Koike 531e6938cc1SHelen Koike ret = v4l2_device_register(rkisp1->dev, &rkisp1->v4l2_dev); 532e6938cc1SHelen Koike if (ret) 53313c98102SLaurent Pinchart goto err_pm_runtime_disable; 534e6938cc1SHelen Koike 535e6938cc1SHelen Koike ret = media_device_register(&rkisp1->media_dev); 536e6938cc1SHelen Koike if (ret) { 537e6938cc1SHelen Koike dev_err(dev, "Failed to register media device: %d\n", ret); 538e6938cc1SHelen Koike goto err_unreg_v4l2_dev; 539e6938cc1SHelen Koike } 540e6938cc1SHelen Koike 541e6938cc1SHelen Koike ret = rkisp1_entities_register(rkisp1); 542e6938cc1SHelen Koike if (ret) 543e6938cc1SHelen Koike goto err_unreg_media_dev; 544e6938cc1SHelen Koike 545e6938cc1SHelen Koike rkisp1_debug_init(rkisp1); 546e6938cc1SHelen Koike 547e6938cc1SHelen Koike return 0; 548e6938cc1SHelen Koike 549e6938cc1SHelen Koike err_unreg_media_dev: 550e6938cc1SHelen Koike media_device_unregister(&rkisp1->media_dev); 551e6938cc1SHelen Koike err_unreg_v4l2_dev: 552e6938cc1SHelen Koike v4l2_device_unregister(&rkisp1->v4l2_dev); 55313c98102SLaurent Pinchart err_pm_runtime_disable: 554e6938cc1SHelen Koike pm_runtime_disable(&pdev->dev); 555e6938cc1SHelen Koike return ret; 556e6938cc1SHelen Koike } 557e6938cc1SHelen Koike 558e6938cc1SHelen Koike static int rkisp1_remove(struct platform_device *pdev) 559e6938cc1SHelen Koike { 560e6938cc1SHelen Koike struct rkisp1_device *rkisp1 = platform_get_drvdata(pdev); 561e6938cc1SHelen Koike 5623c8c1539SSakari Ailus v4l2_async_nf_unregister(&rkisp1->notifier); 5633c8c1539SSakari Ailus v4l2_async_nf_cleanup(&rkisp1->notifier); 564e6938cc1SHelen Koike 5656ff02276SLaurent Pinchart rkisp1_entities_unregister(rkisp1); 5668682037dSLaurent Pinchart rkisp1_debug_cleanup(rkisp1); 567e6938cc1SHelen Koike 568e6938cc1SHelen Koike media_device_unregister(&rkisp1->media_dev); 569e6938cc1SHelen Koike v4l2_device_unregister(&rkisp1->v4l2_dev); 570e6938cc1SHelen Koike 571e6938cc1SHelen Koike pm_runtime_disable(&pdev->dev); 572e6938cc1SHelen Koike 573e6938cc1SHelen Koike return 0; 574e6938cc1SHelen Koike } 575e6938cc1SHelen Koike 576e6938cc1SHelen Koike static struct platform_driver rkisp1_drv = { 577e6938cc1SHelen Koike .driver = { 578e6938cc1SHelen Koike .name = RKISP1_DRIVER_NAME, 579e6938cc1SHelen Koike .of_match_table = of_match_ptr(rkisp1_of_match), 580e6938cc1SHelen Koike .pm = &rkisp1_pm_ops, 581e6938cc1SHelen Koike }, 582e6938cc1SHelen Koike .probe = rkisp1_probe, 583e6938cc1SHelen Koike .remove = rkisp1_remove, 584e6938cc1SHelen Koike }; 585e6938cc1SHelen Koike 586e6938cc1SHelen Koike module_platform_driver(rkisp1_drv); 587e6938cc1SHelen Koike MODULE_DESCRIPTION("Rockchip ISP1 platform driver"); 588e6938cc1SHelen Koike MODULE_LICENSE("Dual MIT/GPL"); 589