linux/drivers/media/platform/atmel/atmel-sama7g5-isc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Microchip eXtended Image Sensor Controller (XISC) driver
   4 *
   5 * Copyright (C) 2019-2021 Microchip Technology, Inc. and its subsidiaries
   6 *
   7 * Author: Eugen Hristev <eugen.hristev@microchip.com>
   8 *
   9 * Sensor-->PFE-->DPC-->WB-->CFA-->CC-->GAM-->VHXS-->CSC-->CBHS-->SUB-->RLP-->DMA-->HIS
  10 *
  11 * ISC video pipeline integrates the following submodules:
  12 * PFE: Parallel Front End to sample the camera sensor input stream
  13 * DPC: Defective Pixel Correction with black offset correction, green disparity
  14 *      correction and defective pixel correction (3 modules total)
  15 *  WB: Programmable white balance in the Bayer domain
  16 * CFA: Color filter array interpolation module
  17 *  CC: Programmable color correction
  18 * GAM: Gamma correction
  19 *VHXS: Vertical and Horizontal Scaler
  20 * CSC: Programmable color space conversion
  21 *CBHS: Contrast Brightness Hue and Saturation control
  22 * SUB: This module performs YCbCr444 to YCbCr420 chrominance subsampling
  23 * RLP: This module performs rounding, range limiting
  24 *      and packing of the incoming data
  25 * DMA: This module performs DMA master accesses to write frames to external RAM
  26 * HIS: Histogram module performs statistic counters on the frames
  27 */
  28
  29#include <linux/clk.h>
  30#include <linux/clkdev.h>
  31#include <linux/clk-provider.h>
  32#include <linux/delay.h>
  33#include <linux/interrupt.h>
  34#include <linux/math64.h>
  35#include <linux/module.h>
  36#include <linux/of.h>
  37#include <linux/of_graph.h>
  38#include <linux/platform_device.h>
  39#include <linux/pm_runtime.h>
  40#include <linux/regmap.h>
  41#include <linux/videodev2.h>
  42
  43#include <media/v4l2-ctrls.h>
  44#include <media/v4l2-device.h>
  45#include <media/v4l2-event.h>
  46#include <media/v4l2-image-sizes.h>
  47#include <media/v4l2-ioctl.h>
  48#include <media/v4l2-fwnode.h>
  49#include <media/v4l2-subdev.h>
  50#include <media/videobuf2-dma-contig.h>
  51
  52#include "atmel-isc-regs.h"
  53#include "atmel-isc.h"
  54
  55#define ISC_SAMA7G5_MAX_SUPPORT_WIDTH   3264
  56#define ISC_SAMA7G5_MAX_SUPPORT_HEIGHT  2464
  57
  58#define ISC_SAMA7G5_PIPELINE \
  59        (WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
  60        CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
  61
  62/* This is a list of the formats that the ISC can *output* */
  63static const struct isc_format sama7g5_controller_formats[] = {
  64        {
  65                .fourcc         = V4L2_PIX_FMT_ARGB444,
  66        },
  67        {
  68                .fourcc         = V4L2_PIX_FMT_ARGB555,
  69        },
  70        {
  71                .fourcc         = V4L2_PIX_FMT_RGB565,
  72        },
  73        {
  74                .fourcc         = V4L2_PIX_FMT_ABGR32,
  75        },
  76        {
  77                .fourcc         = V4L2_PIX_FMT_XBGR32,
  78        },
  79        {
  80                .fourcc         = V4L2_PIX_FMT_YUV420,
  81        },
  82        {
  83                .fourcc         = V4L2_PIX_FMT_UYVY,
  84        },
  85        {
  86                .fourcc         = V4L2_PIX_FMT_VYUY,
  87        },
  88        {
  89                .fourcc         = V4L2_PIX_FMT_YUYV,
  90        },
  91        {
  92                .fourcc         = V4L2_PIX_FMT_YUV422P,
  93        },
  94        {
  95                .fourcc         = V4L2_PIX_FMT_GREY,
  96        },
  97        {
  98                .fourcc         = V4L2_PIX_FMT_Y10,
  99        },
 100        {
 101                .fourcc         = V4L2_PIX_FMT_Y16,
 102        },
 103};
 104
 105/* This is a list of formats that the ISC can receive as *input* */
 106static struct isc_format sama7g5_formats_list[] = {
 107        {
 108                .fourcc         = V4L2_PIX_FMT_SBGGR8,
 109                .mbus_code      = MEDIA_BUS_FMT_SBGGR8_1X8,
 110                .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
 111                .cfa_baycfg     = ISC_BAY_CFG_BGBG,
 112        },
 113        {
 114                .fourcc         = V4L2_PIX_FMT_SGBRG8,
 115                .mbus_code      = MEDIA_BUS_FMT_SGBRG8_1X8,
 116                .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
 117                .cfa_baycfg     = ISC_BAY_CFG_GBGB,
 118        },
 119        {
 120                .fourcc         = V4L2_PIX_FMT_SGRBG8,
 121                .mbus_code      = MEDIA_BUS_FMT_SGRBG8_1X8,
 122                .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
 123                .cfa_baycfg     = ISC_BAY_CFG_GRGR,
 124        },
 125        {
 126                .fourcc         = V4L2_PIX_FMT_SRGGB8,
 127                .mbus_code      = MEDIA_BUS_FMT_SRGGB8_1X8,
 128                .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
 129                .cfa_baycfg     = ISC_BAY_CFG_RGRG,
 130        },
 131        {
 132                .fourcc         = V4L2_PIX_FMT_SBGGR10,
 133                .mbus_code      = MEDIA_BUS_FMT_SBGGR10_1X10,
 134                .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
 135                .cfa_baycfg     = ISC_BAY_CFG_RGRG,
 136        },
 137        {
 138                .fourcc         = V4L2_PIX_FMT_SGBRG10,
 139                .mbus_code      = MEDIA_BUS_FMT_SGBRG10_1X10,
 140                .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
 141                .cfa_baycfg     = ISC_BAY_CFG_GBGB,
 142        },
 143        {
 144                .fourcc         = V4L2_PIX_FMT_SGRBG10,
 145                .mbus_code      = MEDIA_BUS_FMT_SGRBG10_1X10,
 146                .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
 147                .cfa_baycfg     = ISC_BAY_CFG_GRGR,
 148        },
 149        {
 150                .fourcc         = V4L2_PIX_FMT_SRGGB10,
 151                .mbus_code      = MEDIA_BUS_FMT_SRGGB10_1X10,
 152                .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
 153                .cfa_baycfg     = ISC_BAY_CFG_RGRG,
 154        },
 155        {
 156                .fourcc         = V4L2_PIX_FMT_SBGGR12,
 157                .mbus_code      = MEDIA_BUS_FMT_SBGGR12_1X12,
 158                .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TWELVE,
 159                .cfa_baycfg     = ISC_BAY_CFG_BGBG,
 160        },
 161        {
 162                .fourcc         = V4L2_PIX_FMT_SGBRG12,
 163                .mbus_code      = MEDIA_BUS_FMT_SGBRG12_1X12,
 164                .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TWELVE,
 165                .cfa_baycfg     = ISC_BAY_CFG_GBGB,
 166        },
 167        {
 168                .fourcc         = V4L2_PIX_FMT_SGRBG12,
 169                .mbus_code      = MEDIA_BUS_FMT_SGRBG12_1X12,
 170                .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TWELVE,
 171                .cfa_baycfg     = ISC_BAY_CFG_GRGR,
 172        },
 173        {
 174                .fourcc         = V4L2_PIX_FMT_SRGGB12,
 175                .mbus_code      = MEDIA_BUS_FMT_SRGGB12_1X12,
 176                .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TWELVE,
 177                .cfa_baycfg     = ISC_BAY_CFG_RGRG,
 178        },
 179        {
 180                .fourcc         = V4L2_PIX_FMT_GREY,
 181                .mbus_code      = MEDIA_BUS_FMT_Y8_1X8,
 182                .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
 183        },
 184        {
 185                .fourcc         = V4L2_PIX_FMT_YUYV,
 186                .mbus_code      = MEDIA_BUS_FMT_YUYV8_2X8,
 187                .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
 188        },
 189        {
 190                .fourcc         = V4L2_PIX_FMT_UYVY,
 191                .mbus_code      = MEDIA_BUS_FMT_YUYV8_2X8,
 192                .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
 193        },
 194        {
 195                .fourcc         = V4L2_PIX_FMT_RGB565,
 196                .mbus_code      = MEDIA_BUS_FMT_RGB565_2X8_LE,
 197                .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
 198        },
 199        {
 200                .fourcc         = V4L2_PIX_FMT_Y10,
 201                .mbus_code      = MEDIA_BUS_FMT_Y10_1X10,
 202                .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
 203        },
 204
 205};
 206
 207static void isc_sama7g5_config_csc(struct isc_device *isc)
 208{
 209        struct regmap *regmap = isc->regmap;
 210
 211        /* Convert RGB to YUV */
 212        regmap_write(regmap, ISC_CSC_YR_YG + isc->offsets.csc,
 213                     0x42 | (0x81 << 16));
 214        regmap_write(regmap, ISC_CSC_YB_OY + isc->offsets.csc,
 215                     0x19 | (0x10 << 16));
 216        regmap_write(regmap, ISC_CSC_CBR_CBG + isc->offsets.csc,
 217                     0xFDA | (0xFB6 << 16));
 218        regmap_write(regmap, ISC_CSC_CBB_OCB + isc->offsets.csc,
 219                     0x70 | (0x80 << 16));
 220        regmap_write(regmap, ISC_CSC_CRR_CRG + isc->offsets.csc,
 221                     0x70 | (0xFA2 << 16));
 222        regmap_write(regmap, ISC_CSC_CRB_OCR + isc->offsets.csc,
 223                     0xFEE | (0x80 << 16));
 224}
 225
 226static void isc_sama7g5_config_cbc(struct isc_device *isc)
 227{
 228        struct regmap *regmap = isc->regmap;
 229
 230        /* Configure what is set via v4l2 ctrls */
 231        regmap_write(regmap, ISC_CBC_BRIGHT + isc->offsets.cbc, isc->ctrls.brightness);
 232        regmap_write(regmap, ISC_CBC_CONTRAST + isc->offsets.cbc, isc->ctrls.contrast);
 233        /* Configure Hue and Saturation as neutral midpoint */
 234        regmap_write(regmap, ISC_CBCHS_HUE, 0);
 235        regmap_write(regmap, ISC_CBCHS_SAT, (1 << 4));
 236}
 237
 238static void isc_sama7g5_config_cc(struct isc_device *isc)
 239{
 240        struct regmap *regmap = isc->regmap;
 241
 242        /* Configure each register at the neutral fixed point 1.0 or 0.0 */
 243        regmap_write(regmap, ISC_CC_RR_RG, (1 << 8));
 244        regmap_write(regmap, ISC_CC_RB_OR, 0);
 245        regmap_write(regmap, ISC_CC_GR_GG, (1 << 8) << 16);
 246        regmap_write(regmap, ISC_CC_GB_OG, 0);
 247        regmap_write(regmap, ISC_CC_BR_BG, 0);
 248        regmap_write(regmap, ISC_CC_BB_OB, (1 << 8));
 249}
 250
 251static void isc_sama7g5_config_ctrls(struct isc_device *isc,
 252                                     const struct v4l2_ctrl_ops *ops)
 253{
 254        struct isc_ctrls *ctrls = &isc->ctrls;
 255        struct v4l2_ctrl_handler *hdl = &ctrls->handler;
 256
 257        ctrls->contrast = 16;
 258
 259        v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 16);
 260}
 261
 262static void isc_sama7g5_config_dpc(struct isc_device *isc)
 263{
 264        u32 bay_cfg = isc->config.sd_format->cfa_baycfg;
 265        struct regmap *regmap = isc->regmap;
 266
 267        regmap_update_bits(regmap, ISC_DPC_CFG, ISC_DPC_CFG_BLOFF_MASK,
 268                           (64 << ISC_DPC_CFG_BLOFF_SHIFT));
 269        regmap_update_bits(regmap, ISC_DPC_CFG, ISC_DPC_CFG_BAYCFG_MASK,
 270                           (bay_cfg << ISC_DPC_CFG_BAYCFG_SHIFT));
 271}
 272
 273static void isc_sama7g5_config_gam(struct isc_device *isc)
 274{
 275        struct regmap *regmap = isc->regmap;
 276
 277        regmap_update_bits(regmap, ISC_GAM_CTRL, ISC_GAM_CTRL_BIPART,
 278                           ISC_GAM_CTRL_BIPART);
 279}
 280
 281static void isc_sama7g5_config_rlp(struct isc_device *isc)
 282{
 283        struct regmap *regmap = isc->regmap;
 284        u32 rlp_mode = isc->config.rlp_cfg_mode;
 285
 286        regmap_update_bits(regmap, ISC_RLP_CFG + isc->offsets.rlp,
 287                           ISC_RLP_CFG_MODE_MASK | ISC_RLP_CFG_LSH |
 288                           ISC_RLP_CFG_YMODE_MASK, rlp_mode);
 289}
 290
 291static void isc_sama7g5_adapt_pipeline(struct isc_device *isc)
 292{
 293        isc->try_config.bits_pipeline &= ISC_SAMA7G5_PIPELINE;
 294}
 295
 296/* Gamma table with gamma 1/2.2 */
 297static const u32 isc_sama7g5_gamma_table[][GAMMA_ENTRIES] = {
 298        /* index 0 --> gamma bipartite */
 299        {
 300              0x980,  0x4c0320,  0x650260,  0x7801e0,  0x8701a0,  0x940180,
 301           0xa00160,  0xab0120,  0xb40120,  0xbd0120,  0xc60100,  0xce0100,
 302           0xd600e0,  0xdd00e0,  0xe400e0,  0xeb00c0,  0xf100c0,  0xf700c0,
 303           0xfd00c0, 0x10300a0, 0x10800c0, 0x10e00a0, 0x11300a0, 0x11800a0,
 304          0x11d00a0, 0x12200a0, 0x12700a0, 0x12c0080, 0x13000a0, 0x1350080,
 305          0x13900a0, 0x13e0080, 0x1420076, 0x17d0062, 0x1ae0054, 0x1d8004a,
 306          0x1fd0044, 0x21f003e, 0x23e003a, 0x25b0036, 0x2760032, 0x28f0030,
 307          0x2a7002e, 0x2be002c, 0x2d4002c, 0x2ea0028, 0x2fe0028, 0x3120026,
 308          0x3250024, 0x3370024, 0x3490022, 0x35a0022, 0x36b0020, 0x37b0020,
 309          0x38b0020, 0x39b001e, 0x3aa001e, 0x3b9001c, 0x3c7001c, 0x3d5001c,
 310          0x3e3001c, 0x3f1001c, 0x3ff001a, 0x40c001a },
 311};
 312
 313static int xisc_parse_dt(struct device *dev, struct isc_device *isc)
 314{
 315        struct device_node *np = dev->of_node;
 316        struct device_node *epn = NULL;
 317        struct isc_subdev_entity *subdev_entity;
 318        unsigned int flags;
 319        int ret;
 320        bool mipi_mode;
 321
 322        INIT_LIST_HEAD(&isc->subdev_entities);
 323
 324        mipi_mode = of_property_read_bool(np, "microchip,mipi-mode");
 325
 326        while (1) {
 327                struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 };
 328
 329                epn = of_graph_get_next_endpoint(np, epn);
 330                if (!epn)
 331                        return 0;
 332
 333                ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn),
 334                                                 &v4l2_epn);
 335                if (ret) {
 336                        ret = -EINVAL;
 337                        dev_err(dev, "Could not parse the endpoint\n");
 338                        break;
 339                }
 340
 341                subdev_entity = devm_kzalloc(dev, sizeof(*subdev_entity),
 342                                             GFP_KERNEL);
 343                if (!subdev_entity) {
 344                        ret = -ENOMEM;
 345                        break;
 346                }
 347                subdev_entity->epn = epn;
 348
 349                flags = v4l2_epn.bus.parallel.flags;
 350
 351                if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
 352                        subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW;
 353
 354                if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
 355                        subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW;
 356
 357                if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
 358                        subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW;
 359
 360                if (v4l2_epn.bus_type == V4L2_MBUS_BT656)
 361                        subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC |
 362                                        ISC_PFE_CFG0_CCIR656;
 363
 364                if (mipi_mode)
 365                        subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_MIPI;
 366
 367                list_add_tail(&subdev_entity->list, &isc->subdev_entities);
 368        }
 369        of_node_put(epn);
 370
 371        return ret;
 372}
 373
 374static int microchip_xisc_probe(struct platform_device *pdev)
 375{
 376        struct device *dev = &pdev->dev;
 377        struct isc_device *isc;
 378        struct resource *res;
 379        void __iomem *io_base;
 380        struct isc_subdev_entity *subdev_entity;
 381        int irq;
 382        int ret;
 383        u32 ver;
 384
 385        isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL);
 386        if (!isc)
 387                return -ENOMEM;
 388
 389        platform_set_drvdata(pdev, isc);
 390        isc->dev = dev;
 391
 392        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 393        io_base = devm_ioremap_resource(dev, res);
 394        if (IS_ERR(io_base))
 395                return PTR_ERR(io_base);
 396
 397        isc->regmap = devm_regmap_init_mmio(dev, io_base, &isc_regmap_config);
 398        if (IS_ERR(isc->regmap)) {
 399                ret = PTR_ERR(isc->regmap);
 400                dev_err(dev, "failed to init register map: %d\n", ret);
 401                return ret;
 402        }
 403
 404        irq = platform_get_irq(pdev, 0);
 405        if (irq < 0)
 406                return irq;
 407
 408        ret = devm_request_irq(dev, irq, isc_interrupt, 0,
 409                               "microchip-sama7g5-xisc", isc);
 410        if (ret < 0) {
 411                dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
 412                        irq, ret);
 413                return ret;
 414        }
 415
 416        isc->gamma_table = isc_sama7g5_gamma_table;
 417        isc->gamma_max = 0;
 418
 419        isc->max_width = ISC_SAMA7G5_MAX_SUPPORT_WIDTH;
 420        isc->max_height = ISC_SAMA7G5_MAX_SUPPORT_HEIGHT;
 421
 422        isc->config_dpc = isc_sama7g5_config_dpc;
 423        isc->config_csc = isc_sama7g5_config_csc;
 424        isc->config_cbc = isc_sama7g5_config_cbc;
 425        isc->config_cc = isc_sama7g5_config_cc;
 426        isc->config_gam = isc_sama7g5_config_gam;
 427        isc->config_rlp = isc_sama7g5_config_rlp;
 428        isc->config_ctrls = isc_sama7g5_config_ctrls;
 429
 430        isc->adapt_pipeline = isc_sama7g5_adapt_pipeline;
 431
 432        isc->offsets.csc = ISC_SAMA7G5_CSC_OFFSET;
 433        isc->offsets.cbc = ISC_SAMA7G5_CBC_OFFSET;
 434        isc->offsets.sub422 = ISC_SAMA7G5_SUB422_OFFSET;
 435        isc->offsets.sub420 = ISC_SAMA7G5_SUB420_OFFSET;
 436        isc->offsets.rlp = ISC_SAMA7G5_RLP_OFFSET;
 437        isc->offsets.his = ISC_SAMA7G5_HIS_OFFSET;
 438        isc->offsets.dma = ISC_SAMA7G5_DMA_OFFSET;
 439        isc->offsets.version = ISC_SAMA7G5_VERSION_OFFSET;
 440        isc->offsets.his_entry = ISC_SAMA7G5_HIS_ENTRY_OFFSET;
 441
 442        isc->controller_formats = sama7g5_controller_formats;
 443        isc->controller_formats_size = ARRAY_SIZE(sama7g5_controller_formats);
 444        isc->formats_list = sama7g5_formats_list;
 445        isc->formats_list_size = ARRAY_SIZE(sama7g5_formats_list);
 446
 447        /* sama7g5-isc RAM access port is full AXI4 - 32 bits per beat */
 448        isc->dcfg = ISC_DCFG_YMBSIZE_BEATS32 | ISC_DCFG_CMBSIZE_BEATS32;
 449
 450        ret = isc_pipeline_init(isc);
 451        if (ret)
 452                return ret;
 453
 454        isc->hclock = devm_clk_get(dev, "hclock");
 455        if (IS_ERR(isc->hclock)) {
 456                ret = PTR_ERR(isc->hclock);
 457                dev_err(dev, "failed to get hclock: %d\n", ret);
 458                return ret;
 459        }
 460
 461        ret = clk_prepare_enable(isc->hclock);
 462        if (ret) {
 463                dev_err(dev, "failed to enable hclock: %d\n", ret);
 464                return ret;
 465        }
 466
 467        ret = isc_clk_init(isc);
 468        if (ret) {
 469                dev_err(dev, "failed to init isc clock: %d\n", ret);
 470                goto unprepare_hclk;
 471        }
 472
 473        isc->ispck = isc->isc_clks[ISC_ISPCK].clk;
 474
 475        ret = clk_prepare_enable(isc->ispck);
 476        if (ret) {
 477                dev_err(dev, "failed to enable ispck: %d\n", ret);
 478                goto unprepare_hclk;
 479        }
 480
 481        /* ispck should be greater or equal to hclock */
 482        ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock));
 483        if (ret) {
 484                dev_err(dev, "failed to set ispck rate: %d\n", ret);
 485                goto unprepare_clk;
 486        }
 487
 488        ret = v4l2_device_register(dev, &isc->v4l2_dev);
 489        if (ret) {
 490                dev_err(dev, "unable to register v4l2 device.\n");
 491                goto unprepare_clk;
 492        }
 493
 494        ret = xisc_parse_dt(dev, isc);
 495        if (ret) {
 496                dev_err(dev, "fail to parse device tree\n");
 497                goto unregister_v4l2_device;
 498        }
 499
 500        if (list_empty(&isc->subdev_entities)) {
 501                dev_err(dev, "no subdev found\n");
 502                ret = -ENODEV;
 503                goto unregister_v4l2_device;
 504        }
 505
 506        list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
 507                struct v4l2_async_subdev *asd;
 508
 509                v4l2_async_notifier_init(&subdev_entity->notifier);
 510
 511                asd = v4l2_async_notifier_add_fwnode_remote_subdev(
 512                                        &subdev_entity->notifier,
 513                                        of_fwnode_handle(subdev_entity->epn),
 514                                        struct v4l2_async_subdev);
 515
 516                of_node_put(subdev_entity->epn);
 517                subdev_entity->epn = NULL;
 518
 519                if (IS_ERR(asd)) {
 520                        ret = PTR_ERR(asd);
 521                        goto cleanup_subdev;
 522                }
 523
 524                subdev_entity->notifier.ops = &isc_async_ops;
 525
 526                ret = v4l2_async_notifier_register(&isc->v4l2_dev,
 527                                                   &subdev_entity->notifier);
 528                if (ret) {
 529                        dev_err(dev, "fail to register async notifier\n");
 530                        goto cleanup_subdev;
 531                }
 532
 533                if (video_is_registered(&isc->video_dev))
 534                        break;
 535        }
 536
 537        pm_runtime_set_active(dev);
 538        pm_runtime_enable(dev);
 539        pm_request_idle(dev);
 540
 541        regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver);
 542        dev_info(dev, "Microchip XISC version %x\n", ver);
 543
 544        return 0;
 545
 546cleanup_subdev:
 547        isc_subdev_cleanup(isc);
 548
 549unregister_v4l2_device:
 550        v4l2_device_unregister(&isc->v4l2_dev);
 551
 552unprepare_clk:
 553        clk_disable_unprepare(isc->ispck);
 554unprepare_hclk:
 555        clk_disable_unprepare(isc->hclock);
 556
 557        isc_clk_cleanup(isc);
 558
 559        return ret;
 560}
 561
 562static int microchip_xisc_remove(struct platform_device *pdev)
 563{
 564        struct isc_device *isc = platform_get_drvdata(pdev);
 565
 566        pm_runtime_disable(&pdev->dev);
 567
 568        isc_subdev_cleanup(isc);
 569
 570        v4l2_device_unregister(&isc->v4l2_dev);
 571
 572        clk_disable_unprepare(isc->ispck);
 573        clk_disable_unprepare(isc->hclock);
 574
 575        isc_clk_cleanup(isc);
 576
 577        return 0;
 578}
 579
 580static int __maybe_unused xisc_runtime_suspend(struct device *dev)
 581{
 582        struct isc_device *isc = dev_get_drvdata(dev);
 583
 584        clk_disable_unprepare(isc->ispck);
 585        clk_disable_unprepare(isc->hclock);
 586
 587        return 0;
 588}
 589
 590static int __maybe_unused xisc_runtime_resume(struct device *dev)
 591{
 592        struct isc_device *isc = dev_get_drvdata(dev);
 593        int ret;
 594
 595        ret = clk_prepare_enable(isc->hclock);
 596        if (ret)
 597                return ret;
 598
 599        ret = clk_prepare_enable(isc->ispck);
 600        if (ret)
 601                clk_disable_unprepare(isc->hclock);
 602
 603        return ret;
 604}
 605
 606static const struct dev_pm_ops microchip_xisc_dev_pm_ops = {
 607        SET_RUNTIME_PM_OPS(xisc_runtime_suspend, xisc_runtime_resume, NULL)
 608};
 609
 610static const struct of_device_id microchip_xisc_of_match[] = {
 611        { .compatible = "microchip,sama7g5-isc" },
 612        { }
 613};
 614MODULE_DEVICE_TABLE(of, microchip_xisc_of_match);
 615
 616static struct platform_driver microchip_xisc_driver = {
 617        .probe  = microchip_xisc_probe,
 618        .remove = microchip_xisc_remove,
 619        .driver = {
 620                .name           = "microchip-sama7g5-xisc",
 621                .pm             = &microchip_xisc_dev_pm_ops,
 622                .of_match_table = of_match_ptr(microchip_xisc_of_match),
 623        },
 624};
 625
 626module_platform_driver(microchip_xisc_driver);
 627
 628MODULE_AUTHOR("Eugen Hristev <eugen.hristev@microchip.com>");
 629MODULE_DESCRIPTION("The V4L2 driver for Microchip-XISC");
 630MODULE_LICENSE("GPL v2");
 631