FILE
atmel-sama7g5-isc.c
File preview with syntax highlighting.
linux-6.19.14/drivers/staging/media/deprecated/atmel/atmel-sama7g5-isc.c
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 .fourcc = V4L2_PIX_FMT_ARGB555, 68 }, { 69 .fourcc = V4L2_PIX_FMT_RGB565, 70 }, { 71 .fourcc = V4L2_PIX_FMT_ABGR32, 72 }, { 73 .fourcc = V4L2_PIX_FMT_XBGR32, 74 }, { 75 .fourcc = V4L2_PIX_FMT_YUV420, 76 }, { 77 .fourcc = V4L2_PIX_FMT_UYVY, 78 }, { 79 .fourcc = V4L2_PIX_FMT_VYUY, 80 }, { 81 .fourcc = V4L2_PIX_FMT_YUYV, 82 }, { 83 .fourcc = V4L2_PIX_FMT_YUV422P, 84 }, { 85 .fourcc = V4L2_PIX_FMT_GREY, 86 }, { 87 .fourcc = V4L2_PIX_FMT_Y10, 88 }, { 89 .fourcc = V4L2_PIX_FMT_Y16, 90 }, { 91 .fourcc = V4L2_PIX_FMT_SBGGR8, 92 }, { 93 .fourcc = V4L2_PIX_FMT_SGBRG8, 94 }, { 95 .fourcc = V4L2_PIX_FMT_SGRBG8, 96 }, { 97 .fourcc = V4L2_PIX_FMT_SRGGB8, 98 }, { 99 .fourcc = V4L2_PIX_FMT_SBGGR10, 100 }, { 101 .fourcc = V4L2_PIX_FMT_SGBRG10, 102 }, { 103 .fourcc = V4L2_PIX_FMT_SGRBG10, 104 }, { 105 .fourcc = V4L2_PIX_FMT_SRGGB10, 106 }, 107}; 108 109/* This is a list of formats that the ISC can receive as *input* */ 110static struct isc_format sama7g5_formats_list[] = { 111 { 112 .fourcc = V4L2_PIX_FMT_SBGGR8, 113 .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, 114 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, 115 .cfa_baycfg = ISC_BAY_CFG_BGBG, 116 }, 117 { 118 .fourcc = V4L2_PIX_FMT_SGBRG8, 119 .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, 120 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, 121 .cfa_baycfg = ISC_BAY_CFG_GBGB, 122 }, 123 { 124 .fourcc = V4L2_PIX_FMT_SGRBG8, 125 .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, 126 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, 127 .cfa_baycfg = ISC_BAY_CFG_GRGR, 128 }, 129 { 130 .fourcc = V4L2_PIX_FMT_SRGGB8, 131 .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, 132 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, 133 .cfa_baycfg = ISC_BAY_CFG_RGRG, 134 }, 135 { 136 .fourcc = V4L2_PIX_FMT_SBGGR10, 137 .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, 138 .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, 139 .cfa_baycfg = ISC_BAY_CFG_RGRG, 140 }, 141 { 142 .fourcc = V4L2_PIX_FMT_SGBRG10, 143 .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, 144 .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, 145 .cfa_baycfg = ISC_BAY_CFG_GBGB, 146 }, 147 { 148 .fourcc = V4L2_PIX_FMT_SGRBG10, 149 .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, 150 .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, 151 .cfa_baycfg = ISC_BAY_CFG_GRGR, 152 }, 153 { 154 .fourcc = V4L2_PIX_FMT_SRGGB10, 155 .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, 156 .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, 157 .cfa_baycfg = ISC_BAY_CFG_RGRG, 158 }, 159 { 160 .fourcc = V4L2_PIX_FMT_SBGGR12, 161 .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, 162 .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, 163 .cfa_baycfg = ISC_BAY_CFG_BGBG, 164 }, 165 { 166 .fourcc = V4L2_PIX_FMT_SGBRG12, 167 .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, 168 .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, 169 .cfa_baycfg = ISC_BAY_CFG_GBGB, 170 }, 171 { 172 .fourcc = V4L2_PIX_FMT_SGRBG12, 173 .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, 174 .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, 175 .cfa_baycfg = ISC_BAY_CFG_GRGR, 176 }, 177 { 178 .fourcc = V4L2_PIX_FMT_SRGGB12, 179 .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, 180 .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, 181 .cfa_baycfg = ISC_BAY_CFG_RGRG, 182 }, 183 { 184 .fourcc = V4L2_PIX_FMT_GREY, 185 .mbus_code = MEDIA_BUS_FMT_Y8_1X8, 186 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, 187 }, 188 { 189 .fourcc = V4L2_PIX_FMT_YUYV, 190 .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, 191 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, 192 }, 193 { 194 .fourcc = V4L2_PIX_FMT_UYVY, 195 .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, 196 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, 197 }, 198 { 199 .fourcc = V4L2_PIX_FMT_RGB565, 200 .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE, 201 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, 202 }, 203 { 204 .fourcc = V4L2_PIX_FMT_Y10, 205 .mbus_code = MEDIA_BUS_FMT_Y10_1X10, 206 .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, 207 }, 208}; 209 210static void isc_sama7g5_config_csc(struct isc_device *isc) 211{ 212 struct regmap *regmap = isc->regmap; 213 214 /* Convert RGB to YUV */ 215 regmap_write(regmap, ISC_CSC_YR_YG + isc->offsets.csc, 216 0x42 | (0x81 << 16)); 217 regmap_write(regmap, ISC_CSC_YB_OY + isc->offsets.csc, 218 0x19 | (0x10 << 16)); 219 regmap_write(regmap, ISC_CSC_CBR_CBG + isc->offsets.csc, 220 0xFDA | (0xFB6 << 16)); 221 regmap_write(regmap, ISC_CSC_CBB_OCB + isc->offsets.csc, 222 0x70 | (0x80 << 16)); 223 regmap_write(regmap, ISC_CSC_CRR_CRG + isc->offsets.csc, 224 0x70 | (0xFA2 << 16)); 225 regmap_write(regmap, ISC_CSC_CRB_OCR + isc->offsets.csc, 226 0xFEE | (0x80 << 16)); 227} 228 229static void isc_sama7g5_config_cbc(struct isc_device *isc) 230{ 231 struct regmap *regmap = isc->regmap; 232 233 /* Configure what is set via v4l2 ctrls */ 234 regmap_write(regmap, ISC_CBC_BRIGHT + isc->offsets.cbc, isc->ctrls.brightness); 235 regmap_write(regmap, ISC_CBC_CONTRAST + isc->offsets.cbc, isc->ctrls.contrast); 236 /* Configure Hue and Saturation as neutral midpoint */ 237 regmap_write(regmap, ISC_CBCHS_HUE, 0); 238 regmap_write(regmap, ISC_CBCHS_SAT, (1 << 4)); 239} 240 241static void isc_sama7g5_config_cc(struct isc_device *isc) 242{ 243 struct regmap *regmap = isc->regmap; 244 245 /* Configure each register at the neutral fixed point 1.0 or 0.0 */ 246 regmap_write(regmap, ISC_CC_RR_RG, (1 << 8)); 247 regmap_write(regmap, ISC_CC_RB_OR, 0); 248 regmap_write(regmap, ISC_CC_GR_GG, (1 << 8) << 16); 249 regmap_write(regmap, ISC_CC_GB_OG, 0); 250 regmap_write(regmap, ISC_CC_BR_BG, 0); 251 regmap_write(regmap, ISC_CC_BB_OB, (1 << 8)); 252} 253 254static void isc_sama7g5_config_ctrls(struct isc_device *isc, 255 const struct v4l2_ctrl_ops *ops) 256{ 257 struct isc_ctrls *ctrls = &isc->ctrls; 258 struct v4l2_ctrl_handler *hdl = &ctrls->handler; 259 260 ctrls->contrast = 16; 261 262 v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 16); 263} 264 265static void isc_sama7g5_config_dpc(struct isc_device *isc) 266{ 267 u32 bay_cfg = isc->config.sd_format->cfa_baycfg; 268 struct regmap *regmap = isc->regmap; 269 270 regmap_update_bits(regmap, ISC_DPC_CFG, ISC_DPC_CFG_BLOFF_MASK, 271 (64 << ISC_DPC_CFG_BLOFF_SHIFT)); 272 regmap_update_bits(regmap, ISC_DPC_CFG, ISC_DPC_CFG_BAYCFG_MASK, 273 (bay_cfg << ISC_DPC_CFG_BAYCFG_SHIFT)); 274} 275 276static void isc_sama7g5_config_gam(struct isc_device *isc) 277{ 278 struct regmap *regmap = isc->regmap; 279 280 regmap_update_bits(regmap, ISC_GAM_CTRL, ISC_GAM_CTRL_BIPART, 281 ISC_GAM_CTRL_BIPART); 282} 283 284static void isc_sama7g5_config_rlp(struct isc_device *isc) 285{ 286 struct regmap *regmap = isc->regmap; 287 u32 rlp_mode = isc->config.rlp_cfg_mode; 288 289 regmap_update_bits(regmap, ISC_RLP_CFG + isc->offsets.rlp, 290 ISC_RLP_CFG_MODE_MASK | ISC_RLP_CFG_LSH | 291 ISC_RLP_CFG_YMODE_MASK, rlp_mode); 292} 293 294static void isc_sama7g5_adapt_pipeline(struct isc_device *isc) 295{ 296 isc->try_config.bits_pipeline &= ISC_SAMA7G5_PIPELINE; 297} 298 299/* Gamma table with gamma 1/2.2 */ 300static const u32 isc_sama7g5_gamma_table[][GAMMA_ENTRIES] = { 301 /* index 0 --> gamma bipartite */ 302 { 303 0x980, 0x4c0320, 0x650260, 0x7801e0, 0x8701a0, 0x940180, 304 0xa00160, 0xab0120, 0xb40120, 0xbd0120, 0xc60100, 0xce0100, 305 0xd600e0, 0xdd00e0, 0xe400e0, 0xeb00c0, 0xf100c0, 0xf700c0, 306 0xfd00c0, 0x10300a0, 0x10800c0, 0x10e00a0, 0x11300a0, 0x11800a0, 307 0x11d00a0, 0x12200a0, 0x12700a0, 0x12c0080, 0x13000a0, 0x1350080, 308 0x13900a0, 0x13e0080, 0x1420076, 0x17d0062, 0x1ae0054, 0x1d8004a, 309 0x1fd0044, 0x21f003e, 0x23e003a, 0x25b0036, 0x2760032, 0x28f0030, 310 0x2a7002e, 0x2be002c, 0x2d4002c, 0x2ea0028, 0x2fe0028, 0x3120026, 311 0x3250024, 0x3370024, 0x3490022, 0x35a0022, 0x36b0020, 0x37b0020, 312 0x38b0020, 0x39b001e, 0x3aa001e, 0x3b9001c, 0x3c7001c, 0x3d5001c, 313 0x3e3001c, 0x3f1001c, 0x3ff001a, 0x40c001a }, 314}; 315 316static int xisc_parse_dt(struct device *dev, struct isc_device *isc) 317{ 318 struct device_node *np = dev->of_node; 319 struct device_node *epn; 320 struct isc_subdev_entity *subdev_entity; 321 unsigned int flags; 322 int ret = -EINVAL; 323 bool mipi_mode; 324 325 INIT_LIST_HEAD(&isc->subdev_entities); 326 327 mipi_mode = of_property_read_bool(np, "microchip,mipi-mode"); 328 329 for_each_endpoint_of_node(np, epn) { 330 struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 }; 331 332 ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn), 333 &v4l2_epn); 334 if (ret) { 335 ret = -EINVAL; 336 dev_err(dev, "Could not parse the endpoint\n"); 337 break; 338 } 339 340 subdev_entity = devm_kzalloc(dev, sizeof(*subdev_entity), 341 GFP_KERNEL); 342 if (!subdev_entity) { 343 ret = -ENOMEM; 344 break; 345 } 346 subdev_entity->epn = epn; 347 348 flags = v4l2_epn.bus.parallel.flags; 349 350 if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) 351 subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW; 352 353 if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) 354 subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW; 355 356 if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) 357 subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW; 358 359 if (v4l2_epn.bus_type == V4L2_MBUS_BT656) 360 subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC | 361 ISC_PFE_CFG0_CCIR656; 362 363 if (mipi_mode) 364 subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_MIPI; 365 366 list_add_tail(&subdev_entity->list, &isc->subdev_entities); 367 } 368 of_node_put(epn); 369 370 return ret; 371} 372 373static int microchip_xisc_probe(struct platform_device *pdev) 374{ 375 struct device *dev = &pdev->dev; 376 struct isc_device *isc; 377 void __iomem *io_base; 378 struct isc_subdev_entity *subdev_entity; 379 int irq; 380 int ret; 381 u32 ver; 382 383 isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL); 384 if (!isc) 385 return -ENOMEM; 386 387 platform_set_drvdata(pdev, isc); 388 isc->dev = dev; 389 390 io_base = devm_platform_ioremap_resource(pdev, 0); 391 if (IS_ERR(io_base)) 392 return PTR_ERR(io_base); 393 394 isc->regmap = devm_regmap_init_mmio(dev, io_base, &atmel_isc_regmap_config); 395 if (IS_ERR(isc->regmap)) { 396 ret = PTR_ERR(isc->regmap); 397 dev_err(dev, "failed to init register map: %d\n", ret); 398 return ret; 399 } 400 401 irq = platform_get_irq(pdev, 0); 402 if (irq < 0) 403 return irq; 404 405 ret = devm_request_irq(dev, irq, atmel_isc_interrupt, 0, 406 "microchip-sama7g5-xisc", isc); 407 if (ret < 0) { 408 dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n", 409 irq, ret); 410 return ret; 411 } 412 413 isc->gamma_table = isc_sama7g5_gamma_table; 414 isc->gamma_max = 0; 415 416 isc->max_width = ISC_SAMA7G5_MAX_SUPPORT_WIDTH; 417 isc->max_height = ISC_SAMA7G5_MAX_SUPPORT_HEIGHT; 418 419 isc->config_dpc = isc_sama7g5_config_dpc; 420 isc->config_csc = isc_sama7g5_config_csc; 421 isc->config_cbc = isc_sama7g5_config_cbc; 422 isc->config_cc = isc_sama7g5_config_cc; 423 isc->config_gam = isc_sama7g5_config_gam; 424 isc->config_rlp = isc_sama7g5_config_rlp; 425 isc->config_ctrls = isc_sama7g5_config_ctrls; 426 427 isc->adapt_pipeline = isc_sama7g5_adapt_pipeline; 428 429 isc->offsets.csc = ISC_SAMA7G5_CSC_OFFSET; 430 isc->offsets.cbc = ISC_SAMA7G5_CBC_OFFSET; 431 isc->offsets.sub422 = ISC_SAMA7G5_SUB422_OFFSET; 432 isc->offsets.sub420 = ISC_SAMA7G5_SUB420_OFFSET; 433 isc->offsets.rlp = ISC_SAMA7G5_RLP_OFFSET; 434 isc->offsets.his = ISC_SAMA7G5_HIS_OFFSET; 435 isc->offsets.dma = ISC_SAMA7G5_DMA_OFFSET; 436 isc->offsets.version = ISC_SAMA7G5_VERSION_OFFSET; 437 isc->offsets.his_entry = ISC_SAMA7G5_HIS_ENTRY_OFFSET; 438 439 isc->controller_formats = sama7g5_controller_formats; 440 isc->controller_formats_size = ARRAY_SIZE(sama7g5_controller_formats); 441 isc->formats_list = sama7g5_formats_list; 442 isc->formats_list_size = ARRAY_SIZE(sama7g5_formats_list); 443 444 /* sama7g5-isc RAM access port is full AXI4 - 32 bits per beat */ 445 isc->dcfg = ISC_DCFG_YMBSIZE_BEATS32 | ISC_DCFG_CMBSIZE_BEATS32; 446 447 /* sama7g5-isc : ISPCK does not exist, ISC is clocked by MCK */ 448 isc->ispck_required = false; 449 450 ret = atmel_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 = atmel_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 ret = v4l2_device_register(dev, &isc->v4l2_dev); 474 if (ret) { 475 dev_err(dev, "unable to register v4l2 device.\n"); 476 goto unprepare_hclk; 477 } 478 479 ret = xisc_parse_dt(dev, isc); 480 if (ret) { 481 dev_err(dev, "fail to parse device tree\n"); 482 goto unregister_v4l2_device; 483 } 484 485 if (list_empty(&isc->subdev_entities)) { 486 dev_err(dev, "no subdev found\n"); 487 ret = -ENODEV; 488 goto unregister_v4l2_device; 489 } 490 491 list_for_each_entry(subdev_entity, &isc->subdev_entities, list) { 492 struct v4l2_async_connection *asd; 493 struct fwnode_handle *fwnode = 494 of_fwnode_handle(subdev_entity->epn); 495 496 v4l2_async_nf_init(&subdev_entity->notifier, &isc->v4l2_dev); 497 498 asd = v4l2_async_nf_add_fwnode_remote(&subdev_entity->notifier, 499 fwnode, 500 struct v4l2_async_connection); 501 502 of_node_put(subdev_entity->epn); 503 subdev_entity->epn = NULL; 504 505 if (IS_ERR(asd)) { 506 ret = PTR_ERR(asd); 507 goto cleanup_subdev; 508 } 509 510 subdev_entity->notifier.ops = &atmel_isc_async_ops; 511 512 ret = v4l2_async_nf_register(&subdev_entity->notifier); 513 if (ret) { 514 dev_err(dev, "fail to register async notifier\n"); 515 goto cleanup_subdev; 516 } 517 518 if (video_is_registered(&isc->video_dev)) 519 break; 520 } 521 522 pm_runtime_set_active(dev); 523 pm_runtime_enable(dev); 524 pm_request_idle(dev); 525 526 regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver); 527 dev_info(dev, "Microchip XISC version %x\n", ver); 528 529 return 0; 530 531cleanup_subdev: 532 atmel_isc_subdev_cleanup(isc); 533 534unregister_v4l2_device: 535 v4l2_device_unregister(&isc->v4l2_dev); 536 537unprepare_hclk: 538 clk_disable_unprepare(isc->hclock); 539 540 atmel_isc_clk_cleanup(isc); 541 542 return ret; 543} 544 545static void microchip_xisc_remove(struct platform_device *pdev) 546{ 547 struct isc_device *isc = platform_get_drvdata(pdev); 548 549 pm_runtime_disable(&pdev->dev); 550 551 atmel_isc_subdev_cleanup(isc); 552 553 v4l2_device_unregister(&isc->v4l2_dev); 554 555 clk_disable_unprepare(isc->hclock); 556 557 atmel_isc_clk_cleanup(isc); 558} 559 560static int __maybe_unused xisc_runtime_suspend(struct device *dev) 561{ 562 struct isc_device *isc = dev_get_drvdata(dev); 563 564 clk_disable_unprepare(isc->hclock); 565 566 return 0; 567} 568 569static int __maybe_unused xisc_runtime_resume(struct device *dev) 570{ 571 struct isc_device *isc = dev_get_drvdata(dev); 572 int ret; 573 574 ret = clk_prepare_enable(isc->hclock); 575 if (ret) 576 return ret; 577 578 return ret; 579} 580 581static const struct dev_pm_ops microchip_xisc_dev_pm_ops = { 582 SET_RUNTIME_PM_OPS(xisc_runtime_suspend, xisc_runtime_resume, NULL) 583}; 584 585#if IS_ENABLED(CONFIG_OF) 586static const struct of_device_id microchip_xisc_of_match[] = { 587 { .compatible = "microchip,sama7g5-isc" }, 588 { } 589}; 590MODULE_DEVICE_TABLE(of, microchip_xisc_of_match); 591#endif 592 593static struct platform_driver microchip_xisc_driver = { 594 .probe = microchip_xisc_probe, 595 .remove = microchip_xisc_remove, 596 .driver = { 597 .name = "microchip-sama7g5-xisc", 598 .pm = µchip_xisc_dev_pm_ops, 599 .of_match_table = of_match_ptr(microchip_xisc_of_match), 600 }, 601}; 602 603module_platform_driver(microchip_xisc_driver); 604 605MODULE_AUTHOR("Eugen Hristev <eugen.hristev@microchip.com>"); 606MODULE_DESCRIPTION("The V4L2 driver for Microchip-XISC"); 607MODULE_LICENSE("GPL v2");
~/
Read-only file preview.