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 unsigned int i; 115e6938cc1SHelen Koike int ret; 116e6938cc1SHelen Koike 117e6938cc1SHelen Koike /* create ISP->RSZ->CAP links */ 118e6938cc1SHelen Koike for (i = 0; i < 2; i++) { 119*bc374e17SLaurent Pinchart struct media_entity *resizer = 120*bc374e17SLaurent Pinchart &rkisp1->resizer_devs[i].sd.entity; 121*bc374e17SLaurent Pinchart struct media_entity *capture = 122*bc374e17SLaurent Pinchart &rkisp1->capture_devs[i].vnode.vdev.entity; 123*bc374e17SLaurent Pinchart 124*bc374e17SLaurent Pinchart ret = media_create_pad_link(&rkisp1->isp.sd.entity, 125*bc374e17SLaurent Pinchart RKISP1_ISP_PAD_SOURCE_VIDEO, 126*bc374e17SLaurent Pinchart resizer, RKISP1_RSZ_PAD_SINK, 127e6938cc1SHelen Koike MEDIA_LNK_FL_ENABLED); 128e6938cc1SHelen Koike if (ret) 129e6938cc1SHelen Koike return ret; 130e6938cc1SHelen Koike 131*bc374e17SLaurent Pinchart ret = media_create_pad_link(resizer, RKISP1_RSZ_PAD_SRC, 132*bc374e17SLaurent Pinchart capture, 0, 133*bc374e17SLaurent Pinchart MEDIA_LNK_FL_ENABLED | 134*bc374e17SLaurent Pinchart MEDIA_LNK_FL_IMMUTABLE); 135e6938cc1SHelen Koike if (ret) 136e6938cc1SHelen Koike return ret; 137e6938cc1SHelen Koike } 138e6938cc1SHelen Koike 139e6938cc1SHelen Koike /* params links */ 140*bc374e17SLaurent Pinchart ret = media_create_pad_link(&rkisp1->params.vnode.vdev.entity, 0, 141*bc374e17SLaurent Pinchart &rkisp1->isp.sd.entity, 142*bc374e17SLaurent Pinchart RKISP1_ISP_PAD_SINK_PARAMS, 143*bc374e17SLaurent Pinchart MEDIA_LNK_FL_ENABLED | 144*bc374e17SLaurent Pinchart MEDIA_LNK_FL_IMMUTABLE); 145e6938cc1SHelen Koike if (ret) 146e6938cc1SHelen Koike return ret; 147e6938cc1SHelen Koike 148e6938cc1SHelen Koike /* 3A stats links */ 149*bc374e17SLaurent Pinchart return media_create_pad_link(&rkisp1->isp.sd.entity, 150*bc374e17SLaurent Pinchart RKISP1_ISP_PAD_SOURCE_STATS, 151*bc374e17SLaurent Pinchart &rkisp1->stats.vnode.vdev.entity, 0, 152*bc374e17SLaurent Pinchart MEDIA_LNK_FL_ENABLED | 153*bc374e17SLaurent Pinchart MEDIA_LNK_FL_IMMUTABLE); 154e6938cc1SHelen Koike } 155e6938cc1SHelen Koike 156e6938cc1SHelen Koike static int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier, 157e6938cc1SHelen Koike struct v4l2_subdev *sd, 158e6938cc1SHelen Koike struct v4l2_async_subdev *asd) 159e6938cc1SHelen Koike { 160e6938cc1SHelen Koike struct rkisp1_device *rkisp1 = 161e6938cc1SHelen Koike container_of(notifier, struct rkisp1_device, notifier); 162e6938cc1SHelen Koike struct rkisp1_sensor_async *s_asd = 163e6938cc1SHelen Koike container_of(asd, struct rkisp1_sensor_async, asd); 164*bc374e17SLaurent Pinchart int source_pad; 165e6938cc1SHelen Koike 166e6938cc1SHelen Koike s_asd->pixel_rate_ctrl = v4l2_ctrl_find(sd->ctrl_handler, 167e6938cc1SHelen Koike V4L2_CID_PIXEL_RATE); 168af2dababSLaurent Pinchart if (!s_asd->pixel_rate_ctrl) { 169af2dababSLaurent Pinchart dev_err(rkisp1->dev, "No pixel rate control in subdev %s\n", 170af2dababSLaurent Pinchart sd->name); 171af2dababSLaurent Pinchart return -EINVAL; 172af2dababSLaurent Pinchart } 173af2dababSLaurent Pinchart 174e6938cc1SHelen Koike s_asd->sd = sd; 175e6938cc1SHelen Koike s_asd->dphy = devm_phy_get(rkisp1->dev, "dphy"); 176e6938cc1SHelen Koike if (IS_ERR(s_asd->dphy)) { 177e6938cc1SHelen Koike if (PTR_ERR(s_asd->dphy) != -EPROBE_DEFER) 178e6938cc1SHelen Koike dev_err(rkisp1->dev, "Couldn't get the MIPI D-PHY\n"); 179e6938cc1SHelen Koike return PTR_ERR(s_asd->dphy); 180e6938cc1SHelen Koike } 181e6938cc1SHelen Koike 182e6938cc1SHelen Koike phy_init(s_asd->dphy); 183e6938cc1SHelen Koike 184*bc374e17SLaurent Pinchart /* Create the link to the sensor. */ 185*bc374e17SLaurent Pinchart source_pad = media_entity_get_fwnode_pad(&sd->entity, sd->fwnode, 186*bc374e17SLaurent Pinchart MEDIA_PAD_FL_SOURCE); 187*bc374e17SLaurent Pinchart if (source_pad < 0) { 188*bc374e17SLaurent Pinchart dev_err(rkisp1->dev, "failed to find source pad for %s\n", 189*bc374e17SLaurent Pinchart sd->name); 190*bc374e17SLaurent Pinchart return source_pad; 191*bc374e17SLaurent Pinchart } 192*bc374e17SLaurent Pinchart 193*bc374e17SLaurent Pinchart return media_create_pad_link(&sd->entity, source_pad, 194*bc374e17SLaurent Pinchart &rkisp1->isp.sd.entity, 195*bc374e17SLaurent Pinchart RKISP1_ISP_PAD_SINK_VIDEO, 196*bc374e17SLaurent Pinchart !s_asd->index ? MEDIA_LNK_FL_ENABLED : 0); 197e6938cc1SHelen Koike } 198e6938cc1SHelen Koike 199e6938cc1SHelen Koike static void rkisp1_subdev_notifier_unbind(struct v4l2_async_notifier *notifier, 200e6938cc1SHelen Koike struct v4l2_subdev *sd, 201e6938cc1SHelen Koike struct v4l2_async_subdev *asd) 202e6938cc1SHelen Koike { 203e6938cc1SHelen Koike struct rkisp1_sensor_async *s_asd = 204e6938cc1SHelen Koike container_of(asd, struct rkisp1_sensor_async, asd); 205e6938cc1SHelen Koike 206e6938cc1SHelen Koike phy_exit(s_asd->dphy); 207e6938cc1SHelen Koike } 208e6938cc1SHelen Koike 209e6938cc1SHelen Koike static int rkisp1_subdev_notifier_complete(struct v4l2_async_notifier *notifier) 210e6938cc1SHelen Koike { 211e6938cc1SHelen Koike struct rkisp1_device *rkisp1 = 212e6938cc1SHelen Koike container_of(notifier, struct rkisp1_device, notifier); 213e6938cc1SHelen Koike int ret; 214e6938cc1SHelen Koike 215e6938cc1SHelen Koike ret = rkisp1_create_links(rkisp1); 216e6938cc1SHelen Koike if (ret) 217e6938cc1SHelen Koike return ret; 218e6938cc1SHelen Koike 219e6938cc1SHelen Koike ret = v4l2_device_register_subdev_nodes(&rkisp1->v4l2_dev); 220e6938cc1SHelen Koike if (ret) 221e6938cc1SHelen Koike return ret; 222e6938cc1SHelen Koike 223e6938cc1SHelen Koike dev_dbg(rkisp1->dev, "Async subdev notifier completed\n"); 224e6938cc1SHelen Koike 225e6938cc1SHelen Koike return 0; 226e6938cc1SHelen Koike } 227e6938cc1SHelen Koike 228e6938cc1SHelen Koike static const struct v4l2_async_notifier_operations rkisp1_subdev_notifier_ops = { 229e6938cc1SHelen Koike .bound = rkisp1_subdev_notifier_bound, 230e6938cc1SHelen Koike .unbind = rkisp1_subdev_notifier_unbind, 231e6938cc1SHelen Koike .complete = rkisp1_subdev_notifier_complete, 232e6938cc1SHelen Koike }; 233e6938cc1SHelen Koike 234e6938cc1SHelen Koike static int rkisp1_subdev_notifier(struct rkisp1_device *rkisp1) 235e6938cc1SHelen Koike { 236e6938cc1SHelen Koike struct v4l2_async_notifier *ntf = &rkisp1->notifier; 237e6938cc1SHelen Koike unsigned int next_id = 0; 238*bc374e17SLaurent Pinchart unsigned int index = 0; 239e6938cc1SHelen Koike int ret; 240e6938cc1SHelen Koike 2413c8c1539SSakari Ailus v4l2_async_nf_init(ntf); 242e6938cc1SHelen Koike 243e6938cc1SHelen Koike while (1) { 244e6938cc1SHelen Koike struct v4l2_fwnode_endpoint vep = { 245e6938cc1SHelen Koike .bus_type = V4L2_MBUS_CSI2_DPHY 246e6938cc1SHelen Koike }; 247b01edcbdSLaurent Pinchart struct rkisp1_sensor_async *rk_asd; 248e6938cc1SHelen Koike struct fwnode_handle *ep; 249e6938cc1SHelen Koike 250e6938cc1SHelen Koike ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(rkisp1->dev), 251e6938cc1SHelen Koike 0, next_id, 252e6938cc1SHelen Koike FWNODE_GRAPH_ENDPOINT_NEXT); 253e6938cc1SHelen Koike if (!ep) 254e6938cc1SHelen Koike break; 255e6938cc1SHelen Koike 256e6938cc1SHelen Koike ret = v4l2_fwnode_endpoint_parse(ep, &vep); 257e6938cc1SHelen Koike if (ret) 258e6938cc1SHelen Koike goto err_parse; 259e6938cc1SHelen Koike 2603c8c1539SSakari Ailus rk_asd = v4l2_async_nf_add_fwnode_remote(ntf, ep, 2613c8c1539SSakari Ailus struct 2623c8c1539SSakari Ailus rkisp1_sensor_async); 263b01edcbdSLaurent Pinchart if (IS_ERR(rk_asd)) { 264b01edcbdSLaurent Pinchart ret = PTR_ERR(rk_asd); 265e6938cc1SHelen Koike goto err_parse; 266e6938cc1SHelen Koike } 267e6938cc1SHelen Koike 268*bc374e17SLaurent Pinchart rk_asd->index = index++; 269e6938cc1SHelen Koike rk_asd->mbus_type = vep.bus_type; 270e6938cc1SHelen Koike rk_asd->mbus_flags = vep.bus.mipi_csi2.flags; 271e6938cc1SHelen Koike rk_asd->lanes = vep.bus.mipi_csi2.num_data_lanes; 272e6938cc1SHelen Koike 273e6938cc1SHelen Koike dev_dbg(rkisp1->dev, "registered ep id %d with %d lanes\n", 274e6938cc1SHelen Koike vep.base.id, rk_asd->lanes); 275e6938cc1SHelen Koike 276e6938cc1SHelen Koike next_id = vep.base.id + 1; 277e6938cc1SHelen Koike 278e6938cc1SHelen Koike fwnode_handle_put(ep); 279e6938cc1SHelen Koike 280e6938cc1SHelen Koike continue; 281e6938cc1SHelen Koike err_parse: 282e6938cc1SHelen Koike fwnode_handle_put(ep); 2833c8c1539SSakari Ailus v4l2_async_nf_cleanup(ntf); 284e6938cc1SHelen Koike return ret; 285e6938cc1SHelen Koike } 286e6938cc1SHelen Koike 287e6938cc1SHelen Koike if (next_id == 0) 288e6938cc1SHelen Koike dev_dbg(rkisp1->dev, "no remote subdevice found\n"); 289e6938cc1SHelen Koike ntf->ops = &rkisp1_subdev_notifier_ops; 2903c8c1539SSakari Ailus ret = v4l2_async_nf_register(&rkisp1->v4l2_dev, ntf); 291e6938cc1SHelen Koike if (ret) { 2923c8c1539SSakari Ailus v4l2_async_nf_cleanup(ntf); 293e6938cc1SHelen Koike return ret; 294e6938cc1SHelen Koike } 295e6938cc1SHelen Koike return 0; 296e6938cc1SHelen Koike } 297e6938cc1SHelen Koike 298e6938cc1SHelen Koike /* ---------------------------------------------------------------------------- 299e6938cc1SHelen Koike * Power 300e6938cc1SHelen Koike */ 301e6938cc1SHelen Koike 302e6938cc1SHelen Koike static int __maybe_unused rkisp1_runtime_suspend(struct device *dev) 303e6938cc1SHelen Koike { 304e6938cc1SHelen Koike struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); 305e6938cc1SHelen Koike 306e6938cc1SHelen Koike clk_bulk_disable_unprepare(rkisp1->clk_size, rkisp1->clks); 307e6938cc1SHelen Koike return pinctrl_pm_select_sleep_state(dev); 308e6938cc1SHelen Koike } 309e6938cc1SHelen Koike 310e6938cc1SHelen Koike static int __maybe_unused rkisp1_runtime_resume(struct device *dev) 311e6938cc1SHelen Koike { 312e6938cc1SHelen Koike struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); 313e6938cc1SHelen Koike int ret; 314e6938cc1SHelen Koike 315e6938cc1SHelen Koike ret = pinctrl_pm_select_default_state(dev); 316e6938cc1SHelen Koike if (ret) 317e6938cc1SHelen Koike return ret; 318e6938cc1SHelen Koike ret = clk_bulk_prepare_enable(rkisp1->clk_size, rkisp1->clks); 319e6938cc1SHelen Koike if (ret) 320e6938cc1SHelen Koike return ret; 321e6938cc1SHelen Koike 322e6938cc1SHelen Koike return 0; 323e6938cc1SHelen Koike } 324e6938cc1SHelen Koike 325e6938cc1SHelen Koike static const struct dev_pm_ops rkisp1_pm_ops = { 326e6938cc1SHelen Koike SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 327e6938cc1SHelen Koike pm_runtime_force_resume) 328e6938cc1SHelen Koike SET_RUNTIME_PM_OPS(rkisp1_runtime_suspend, rkisp1_runtime_resume, NULL) 329e6938cc1SHelen Koike }; 330e6938cc1SHelen Koike 331e6938cc1SHelen Koike /* ---------------------------------------------------------------------------- 332e6938cc1SHelen Koike * Core 333e6938cc1SHelen Koike */ 334e6938cc1SHelen Koike 3356ff02276SLaurent Pinchart static void rkisp1_entities_unregister(struct rkisp1_device *rkisp1) 3366ff02276SLaurent Pinchart { 3376ff02276SLaurent Pinchart rkisp1_params_unregister(rkisp1); 3386ff02276SLaurent Pinchart rkisp1_stats_unregister(rkisp1); 3396ff02276SLaurent Pinchart rkisp1_capture_devs_unregister(rkisp1); 3406ff02276SLaurent Pinchart rkisp1_resizer_devs_unregister(rkisp1); 3416ff02276SLaurent Pinchart rkisp1_isp_unregister(rkisp1); 3426ff02276SLaurent Pinchart } 3436ff02276SLaurent Pinchart 344e6938cc1SHelen Koike static int rkisp1_entities_register(struct rkisp1_device *rkisp1) 345e6938cc1SHelen Koike { 346e6938cc1SHelen Koike int ret; 347e6938cc1SHelen Koike 348e6938cc1SHelen Koike ret = rkisp1_isp_register(rkisp1); 349e6938cc1SHelen Koike if (ret) 3506ff02276SLaurent Pinchart goto error; 351e6938cc1SHelen Koike 352e6938cc1SHelen Koike ret = rkisp1_resizer_devs_register(rkisp1); 353e6938cc1SHelen Koike if (ret) 3546ff02276SLaurent Pinchart goto error; 355e6938cc1SHelen Koike 356e6938cc1SHelen Koike ret = rkisp1_capture_devs_register(rkisp1); 357e6938cc1SHelen Koike if (ret) 3586ff02276SLaurent Pinchart goto error; 359e6938cc1SHelen Koike 360e6938cc1SHelen Koike ret = rkisp1_stats_register(rkisp1); 361e6938cc1SHelen Koike if (ret) 3626ff02276SLaurent Pinchart goto error; 363e6938cc1SHelen Koike 364e6938cc1SHelen Koike ret = rkisp1_params_register(rkisp1); 365e6938cc1SHelen Koike if (ret) 3666ff02276SLaurent Pinchart goto error; 367e6938cc1SHelen Koike 368e6938cc1SHelen Koike ret = rkisp1_subdev_notifier(rkisp1); 369e6938cc1SHelen Koike if (ret) { 370e6938cc1SHelen Koike dev_err(rkisp1->dev, 371e6938cc1SHelen Koike "Failed to register subdev notifier(%d)\n", ret); 3726ff02276SLaurent Pinchart goto error; 373e6938cc1SHelen Koike } 374e6938cc1SHelen Koike 375e6938cc1SHelen Koike return 0; 3766ff02276SLaurent Pinchart 3776ff02276SLaurent Pinchart error: 3786ff02276SLaurent Pinchart rkisp1_entities_unregister(rkisp1); 379e6938cc1SHelen Koike return ret; 380e6938cc1SHelen Koike } 381e6938cc1SHelen Koike 382e6938cc1SHelen Koike static irqreturn_t rkisp1_isr(int irq, void *ctx) 383e6938cc1SHelen Koike { 384e6938cc1SHelen Koike /* 385e6938cc1SHelen Koike * Call rkisp1_capture_isr() first to handle the frame that 386e6938cc1SHelen Koike * potentially completed using the current frame_sequence number before 387e6938cc1SHelen Koike * it is potentially incremented by rkisp1_isp_isr() in the vertical 388e6938cc1SHelen Koike * sync. 389e6938cc1SHelen Koike */ 39008818e6aSHeiko Stuebner rkisp1_capture_isr(irq, ctx); 39108818e6aSHeiko Stuebner rkisp1_isp_isr(irq, ctx); 39208818e6aSHeiko Stuebner rkisp1_mipi_isr(irq, ctx); 393e6938cc1SHelen Koike 394e6938cc1SHelen Koike return IRQ_HANDLED; 395e6938cc1SHelen Koike } 396e6938cc1SHelen Koike 397ecf8d36fSHeiko Stuebner static const char * const px30_isp_clks[] = { 398ecf8d36fSHeiko Stuebner "isp", 399ecf8d36fSHeiko Stuebner "aclk", 400ecf8d36fSHeiko Stuebner "hclk", 401ecf8d36fSHeiko Stuebner "pclk", 402ecf8d36fSHeiko Stuebner }; 403ecf8d36fSHeiko Stuebner 404ecf8d36fSHeiko Stuebner static const struct rkisp1_isr_data px30_isp_isrs[] = { 405ecf8d36fSHeiko Stuebner { "isp", rkisp1_isp_isr }, 406ecf8d36fSHeiko Stuebner { "mi", rkisp1_capture_isr }, 407ecf8d36fSHeiko Stuebner { "mipi", rkisp1_mipi_isr }, 408ecf8d36fSHeiko Stuebner }; 409ecf8d36fSHeiko Stuebner 410cdce5b95SLaurent Pinchart static const struct rkisp1_info px30_isp_info = { 411ecf8d36fSHeiko Stuebner .clks = px30_isp_clks, 412ecf8d36fSHeiko Stuebner .clk_size = ARRAY_SIZE(px30_isp_clks), 413ecf8d36fSHeiko Stuebner .isrs = px30_isp_isrs, 414ecf8d36fSHeiko Stuebner .isr_size = ARRAY_SIZE(px30_isp_isrs), 415ecf8d36fSHeiko Stuebner .isp_ver = RKISP1_V12, 416ecf8d36fSHeiko Stuebner }; 417ecf8d36fSHeiko Stuebner 418e6938cc1SHelen Koike static const char * const rk3399_isp_clks[] = { 419e6938cc1SHelen Koike "isp", 420e6938cc1SHelen Koike "aclk", 421e6938cc1SHelen Koike "hclk", 422e6938cc1SHelen Koike }; 423e6938cc1SHelen Koike 42408818e6aSHeiko Stuebner static const struct rkisp1_isr_data rk3399_isp_isrs[] = { 42508818e6aSHeiko Stuebner { NULL, rkisp1_isr }, 42608818e6aSHeiko Stuebner }; 42708818e6aSHeiko Stuebner 428cdce5b95SLaurent Pinchart static const struct rkisp1_info rk3399_isp_info = { 429e6938cc1SHelen Koike .clks = rk3399_isp_clks, 43008818e6aSHeiko Stuebner .clk_size = ARRAY_SIZE(rk3399_isp_clks), 43108818e6aSHeiko Stuebner .isrs = rk3399_isp_isrs, 43208818e6aSHeiko Stuebner .isr_size = ARRAY_SIZE(rk3399_isp_isrs), 433fc672d80SHeiko Stuebner .isp_ver = RKISP1_V10, 434e6938cc1SHelen Koike }; 435e6938cc1SHelen Koike 436e6938cc1SHelen Koike static const struct of_device_id rkisp1_of_match[] = { 437e6938cc1SHelen Koike { 438ecf8d36fSHeiko Stuebner .compatible = "rockchip,px30-cif-isp", 439cdce5b95SLaurent Pinchart .data = &px30_isp_info, 440ecf8d36fSHeiko Stuebner }, 441ecf8d36fSHeiko Stuebner { 442e6938cc1SHelen Koike .compatible = "rockchip,rk3399-cif-isp", 443cdce5b95SLaurent Pinchart .data = &rk3399_isp_info, 444e6938cc1SHelen Koike }, 445e6938cc1SHelen Koike {}, 446e6938cc1SHelen Koike }; 447e6938cc1SHelen Koike MODULE_DEVICE_TABLE(of, rkisp1_of_match); 448e6938cc1SHelen Koike 449e6938cc1SHelen Koike static int rkisp1_probe(struct platform_device *pdev) 450e6938cc1SHelen Koike { 451cdce5b95SLaurent Pinchart const struct rkisp1_info *info; 452e6938cc1SHelen Koike struct device *dev = &pdev->dev; 453e6938cc1SHelen Koike struct rkisp1_device *rkisp1; 454e6938cc1SHelen Koike struct v4l2_device *v4l2_dev; 455e6938cc1SHelen Koike unsigned int i; 456e6938cc1SHelen Koike int ret, irq; 457196179c5SLaurent Pinchart u32 cif_id; 458e6938cc1SHelen Koike 459e6938cc1SHelen Koike rkisp1 = devm_kzalloc(dev, sizeof(*rkisp1), GFP_KERNEL); 460e6938cc1SHelen Koike if (!rkisp1) 461e6938cc1SHelen Koike return -ENOMEM; 462e6938cc1SHelen Koike 4639125aee7SPaul Elder info = of_device_get_match_data(dev); 4649125aee7SPaul Elder rkisp1->info = info; 4659125aee7SPaul Elder 466e6938cc1SHelen Koike dev_set_drvdata(dev, rkisp1); 467e6938cc1SHelen Koike rkisp1->dev = dev; 468e6938cc1SHelen Koike 469e6938cc1SHelen Koike mutex_init(&rkisp1->stream_lock); 470e6938cc1SHelen Koike 471e6938cc1SHelen Koike rkisp1->base_addr = devm_platform_ioremap_resource(pdev, 0); 472e6938cc1SHelen Koike if (IS_ERR(rkisp1->base_addr)) 473e6938cc1SHelen Koike return PTR_ERR(rkisp1->base_addr); 474e6938cc1SHelen Koike 475cdce5b95SLaurent Pinchart for (i = 0; i < info->isr_size; i++) { 476cdce5b95SLaurent Pinchart irq = info->isrs[i].name 477cdce5b95SLaurent Pinchart ? platform_get_irq_byname(pdev, info->isrs[i].name) 478fd83ef8fSLaurent Pinchart : platform_get_irq(pdev, i); 479e6938cc1SHelen Koike if (irq < 0) 480e6938cc1SHelen Koike return irq; 481e6938cc1SHelen Koike 482cdce5b95SLaurent Pinchart ret = devm_request_irq(dev, irq, info->isrs[i].isr, IRQF_SHARED, 483e6938cc1SHelen Koike dev_driver_string(dev), dev); 484e6938cc1SHelen Koike if (ret) { 485e6938cc1SHelen Koike dev_err(dev, "request irq failed: %d\n", ret); 486e6938cc1SHelen Koike return ret; 487e6938cc1SHelen Koike } 48808818e6aSHeiko Stuebner } 489e6938cc1SHelen Koike 490cdce5b95SLaurent Pinchart for (i = 0; i < info->clk_size; i++) 491cdce5b95SLaurent Pinchart rkisp1->clks[i].id = info->clks[i]; 492cdce5b95SLaurent Pinchart ret = devm_clk_bulk_get(dev, info->clk_size, rkisp1->clks); 493e6938cc1SHelen Koike if (ret) 494e6938cc1SHelen Koike return ret; 495cdce5b95SLaurent Pinchart rkisp1->clk_size = info->clk_size; 496e6938cc1SHelen Koike 497e6938cc1SHelen Koike pm_runtime_enable(&pdev->dev); 498e6938cc1SHelen Koike 499196179c5SLaurent Pinchart ret = pm_runtime_resume_and_get(&pdev->dev); 500196179c5SLaurent Pinchart if (ret) 501196179c5SLaurent Pinchart goto err_pm_runtime_disable; 502196179c5SLaurent Pinchart 503196179c5SLaurent Pinchart cif_id = rkisp1_read(rkisp1, RKISP1_CIF_VI_ID); 504196179c5SLaurent Pinchart dev_dbg(rkisp1->dev, "CIF_ID 0x%08x\n", cif_id); 505196179c5SLaurent Pinchart 506196179c5SLaurent Pinchart pm_runtime_put(&pdev->dev); 507196179c5SLaurent Pinchart 508cdce5b95SLaurent Pinchart rkisp1->media_dev.hw_revision = info->isp_ver; 509e6938cc1SHelen Koike strscpy(rkisp1->media_dev.model, RKISP1_DRIVER_NAME, 510e6938cc1SHelen Koike sizeof(rkisp1->media_dev.model)); 511e6938cc1SHelen Koike rkisp1->media_dev.dev = &pdev->dev; 512e6938cc1SHelen Koike strscpy(rkisp1->media_dev.bus_info, RKISP1_BUS_INFO, 513e6938cc1SHelen Koike sizeof(rkisp1->media_dev.bus_info)); 514e6938cc1SHelen Koike media_device_init(&rkisp1->media_dev); 515e6938cc1SHelen Koike 516e6938cc1SHelen Koike v4l2_dev = &rkisp1->v4l2_dev; 517e6938cc1SHelen Koike v4l2_dev->mdev = &rkisp1->media_dev; 518e6938cc1SHelen Koike strscpy(v4l2_dev->name, RKISP1_DRIVER_NAME, sizeof(v4l2_dev->name)); 519e6938cc1SHelen Koike 520e6938cc1SHelen Koike ret = v4l2_device_register(rkisp1->dev, &rkisp1->v4l2_dev); 521e6938cc1SHelen Koike if (ret) 52213c98102SLaurent Pinchart goto err_pm_runtime_disable; 523e6938cc1SHelen Koike 524e6938cc1SHelen Koike ret = media_device_register(&rkisp1->media_dev); 525e6938cc1SHelen Koike if (ret) { 526e6938cc1SHelen Koike dev_err(dev, "Failed to register media device: %d\n", ret); 527e6938cc1SHelen Koike goto err_unreg_v4l2_dev; 528e6938cc1SHelen Koike } 529e6938cc1SHelen Koike 530e6938cc1SHelen Koike ret = rkisp1_entities_register(rkisp1); 531e6938cc1SHelen Koike if (ret) 532e6938cc1SHelen Koike goto err_unreg_media_dev; 533e6938cc1SHelen Koike 534e6938cc1SHelen Koike rkisp1_debug_init(rkisp1); 535e6938cc1SHelen Koike 536e6938cc1SHelen Koike return 0; 537e6938cc1SHelen Koike 538e6938cc1SHelen Koike err_unreg_media_dev: 539e6938cc1SHelen Koike media_device_unregister(&rkisp1->media_dev); 540e6938cc1SHelen Koike err_unreg_v4l2_dev: 541e6938cc1SHelen Koike v4l2_device_unregister(&rkisp1->v4l2_dev); 54213c98102SLaurent Pinchart err_pm_runtime_disable: 543e6938cc1SHelen Koike pm_runtime_disable(&pdev->dev); 544e6938cc1SHelen Koike return ret; 545e6938cc1SHelen Koike } 546e6938cc1SHelen Koike 547e6938cc1SHelen Koike static int rkisp1_remove(struct platform_device *pdev) 548e6938cc1SHelen Koike { 549e6938cc1SHelen Koike struct rkisp1_device *rkisp1 = platform_get_drvdata(pdev); 550e6938cc1SHelen Koike 5513c8c1539SSakari Ailus v4l2_async_nf_unregister(&rkisp1->notifier); 5523c8c1539SSakari Ailus v4l2_async_nf_cleanup(&rkisp1->notifier); 553e6938cc1SHelen Koike 5546ff02276SLaurent Pinchart rkisp1_entities_unregister(rkisp1); 5558682037dSLaurent Pinchart rkisp1_debug_cleanup(rkisp1); 556e6938cc1SHelen Koike 557e6938cc1SHelen Koike media_device_unregister(&rkisp1->media_dev); 558e6938cc1SHelen Koike v4l2_device_unregister(&rkisp1->v4l2_dev); 559e6938cc1SHelen Koike 560e6938cc1SHelen Koike pm_runtime_disable(&pdev->dev); 561e6938cc1SHelen Koike 562e6938cc1SHelen Koike return 0; 563e6938cc1SHelen Koike } 564e6938cc1SHelen Koike 565e6938cc1SHelen Koike static struct platform_driver rkisp1_drv = { 566e6938cc1SHelen Koike .driver = { 567e6938cc1SHelen Koike .name = RKISP1_DRIVER_NAME, 568e6938cc1SHelen Koike .of_match_table = of_match_ptr(rkisp1_of_match), 569e6938cc1SHelen Koike .pm = &rkisp1_pm_ops, 570e6938cc1SHelen Koike }, 571e6938cc1SHelen Koike .probe = rkisp1_probe, 572e6938cc1SHelen Koike .remove = rkisp1_remove, 573e6938cc1SHelen Koike }; 574e6938cc1SHelen Koike 575e6938cc1SHelen Koike module_platform_driver(rkisp1_drv); 576e6938cc1SHelen Koike MODULE_DESCRIPTION("Rockchip ISP1 platform driver"); 577e6938cc1SHelen Koike MODULE_LICENSE("Dual MIT/GPL"); 578