1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (c) 2011-2018 Magewell Electronics Co., Ltd. (Nanjing) 4 * All rights reserved. 5 * Author: Yong Deng <yong.deng@magewell.com> 6 */ 7 8 #include <linux/clk.h> 9 #include <linux/delay.h> 10 #include <linux/dma-mapping.h> 11 #include <linux/err.h> 12 #include <linux/fs.h> 13 #include <linux/interrupt.h> 14 #include <linux/io.h> 15 #include <linux/ioctl.h> 16 #include <linux/module.h> 17 #include <linux/of.h> 18 #include <linux/of_device.h> 19 #include <linux/platform_device.h> 20 #include <linux/pm_runtime.h> 21 #include <linux/regmap.h> 22 #include <linux/reset.h> 23 #include <linux/sched.h> 24 #include <linux/sizes.h> 25 #include <linux/slab.h> 26 27 #include "sun6i_csi.h" 28 #include "sun6i_csi_reg.h" 29 30 /* Helpers */ 31 32 /* TODO add 10&12 bit YUV, RGB support */ 33 bool sun6i_csi_is_format_supported(struct sun6i_csi_device *csi_dev, 34 u32 pixformat, u32 mbus_code) 35 { 36 struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; 37 38 /* 39 * Some video receivers have the ability to be compatible with 40 * 8bit and 16bit bus width. 41 * Identify the media bus format from device tree. 42 */ 43 if ((v4l2->v4l2_ep.bus_type == V4L2_MBUS_PARALLEL 44 || v4l2->v4l2_ep.bus_type == V4L2_MBUS_BT656) 45 && v4l2->v4l2_ep.bus.parallel.bus_width == 16) { 46 switch (pixformat) { 47 case V4L2_PIX_FMT_NV12_16L16: 48 case V4L2_PIX_FMT_NV12: 49 case V4L2_PIX_FMT_NV21: 50 case V4L2_PIX_FMT_NV16: 51 case V4L2_PIX_FMT_NV61: 52 case V4L2_PIX_FMT_YUV420: 53 case V4L2_PIX_FMT_YVU420: 54 case V4L2_PIX_FMT_YUV422P: 55 switch (mbus_code) { 56 case MEDIA_BUS_FMT_UYVY8_1X16: 57 case MEDIA_BUS_FMT_VYUY8_1X16: 58 case MEDIA_BUS_FMT_YUYV8_1X16: 59 case MEDIA_BUS_FMT_YVYU8_1X16: 60 return true; 61 default: 62 dev_dbg(csi_dev->dev, 63 "Unsupported mbus code: 0x%x\n", 64 mbus_code); 65 break; 66 } 67 break; 68 default: 69 dev_dbg(csi_dev->dev, "Unsupported pixformat: 0x%x\n", 70 pixformat); 71 break; 72 } 73 return false; 74 } 75 76 switch (pixformat) { 77 case V4L2_PIX_FMT_SBGGR8: 78 return (mbus_code == MEDIA_BUS_FMT_SBGGR8_1X8); 79 case V4L2_PIX_FMT_SGBRG8: 80 return (mbus_code == MEDIA_BUS_FMT_SGBRG8_1X8); 81 case V4L2_PIX_FMT_SGRBG8: 82 return (mbus_code == MEDIA_BUS_FMT_SGRBG8_1X8); 83 case V4L2_PIX_FMT_SRGGB8: 84 return (mbus_code == MEDIA_BUS_FMT_SRGGB8_1X8); 85 case V4L2_PIX_FMT_SBGGR10: 86 return (mbus_code == MEDIA_BUS_FMT_SBGGR10_1X10); 87 case V4L2_PIX_FMT_SGBRG10: 88 return (mbus_code == MEDIA_BUS_FMT_SGBRG10_1X10); 89 case V4L2_PIX_FMT_SGRBG10: 90 return (mbus_code == MEDIA_BUS_FMT_SGRBG10_1X10); 91 case V4L2_PIX_FMT_SRGGB10: 92 return (mbus_code == MEDIA_BUS_FMT_SRGGB10_1X10); 93 case V4L2_PIX_FMT_SBGGR12: 94 return (mbus_code == MEDIA_BUS_FMT_SBGGR12_1X12); 95 case V4L2_PIX_FMT_SGBRG12: 96 return (mbus_code == MEDIA_BUS_FMT_SGBRG12_1X12); 97 case V4L2_PIX_FMT_SGRBG12: 98 return (mbus_code == MEDIA_BUS_FMT_SGRBG12_1X12); 99 case V4L2_PIX_FMT_SRGGB12: 100 return (mbus_code == MEDIA_BUS_FMT_SRGGB12_1X12); 101 102 case V4L2_PIX_FMT_YUYV: 103 return (mbus_code == MEDIA_BUS_FMT_YUYV8_2X8); 104 case V4L2_PIX_FMT_YVYU: 105 return (mbus_code == MEDIA_BUS_FMT_YVYU8_2X8); 106 case V4L2_PIX_FMT_UYVY: 107 return (mbus_code == MEDIA_BUS_FMT_UYVY8_2X8); 108 case V4L2_PIX_FMT_VYUY: 109 return (mbus_code == MEDIA_BUS_FMT_VYUY8_2X8); 110 111 case V4L2_PIX_FMT_NV12_16L16: 112 case V4L2_PIX_FMT_NV12: 113 case V4L2_PIX_FMT_NV21: 114 case V4L2_PIX_FMT_NV16: 115 case V4L2_PIX_FMT_NV61: 116 case V4L2_PIX_FMT_YUV420: 117 case V4L2_PIX_FMT_YVU420: 118 case V4L2_PIX_FMT_YUV422P: 119 switch (mbus_code) { 120 case MEDIA_BUS_FMT_UYVY8_2X8: 121 case MEDIA_BUS_FMT_VYUY8_2X8: 122 case MEDIA_BUS_FMT_YUYV8_2X8: 123 case MEDIA_BUS_FMT_YVYU8_2X8: 124 return true; 125 default: 126 dev_dbg(csi_dev->dev, "Unsupported mbus code: 0x%x\n", 127 mbus_code); 128 break; 129 } 130 break; 131 132 case V4L2_PIX_FMT_RGB565: 133 return (mbus_code == MEDIA_BUS_FMT_RGB565_2X8_LE); 134 case V4L2_PIX_FMT_RGB565X: 135 return (mbus_code == MEDIA_BUS_FMT_RGB565_2X8_BE); 136 137 case V4L2_PIX_FMT_JPEG: 138 return (mbus_code == MEDIA_BUS_FMT_JPEG_1X8); 139 140 default: 141 dev_dbg(csi_dev->dev, "Unsupported pixformat: 0x%x\n", 142 pixformat); 143 break; 144 } 145 146 return false; 147 } 148 149 int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable) 150 { 151 struct device *dev = csi_dev->dev; 152 struct regmap *regmap = csi_dev->regmap; 153 int ret; 154 155 if (!enable) { 156 regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0); 157 pm_runtime_put(dev); 158 159 return 0; 160 } 161 162 ret = pm_runtime_resume_and_get(dev); 163 if (ret < 0) 164 return ret; 165 166 regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, CSI_EN_CSI_EN); 167 168 return 0; 169 } 170 171 static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_device *csi_dev, 172 u32 mbus_code, u32 pixformat) 173 { 174 /* non-YUV */ 175 if ((mbus_code & 0xF000) != 0x2000) 176 return CSI_INPUT_FORMAT_RAW; 177 178 switch (pixformat) { 179 case V4L2_PIX_FMT_YUYV: 180 case V4L2_PIX_FMT_YVYU: 181 case V4L2_PIX_FMT_UYVY: 182 case V4L2_PIX_FMT_VYUY: 183 return CSI_INPUT_FORMAT_RAW; 184 default: 185 break; 186 } 187 188 /* not support YUV420 input format yet */ 189 dev_dbg(csi_dev->dev, "Select YUV422 as default input format of CSI.\n"); 190 return CSI_INPUT_FORMAT_YUV422; 191 } 192 193 static enum csi_output_fmt 194 get_csi_output_format(struct sun6i_csi_device *csi_dev, u32 pixformat, 195 u32 field) 196 { 197 bool buf_interlaced = false; 198 199 if (field == V4L2_FIELD_INTERLACED 200 || field == V4L2_FIELD_INTERLACED_TB 201 || field == V4L2_FIELD_INTERLACED_BT) 202 buf_interlaced = true; 203 204 switch (pixformat) { 205 case V4L2_PIX_FMT_SBGGR8: 206 case V4L2_PIX_FMT_SGBRG8: 207 case V4L2_PIX_FMT_SGRBG8: 208 case V4L2_PIX_FMT_SRGGB8: 209 return buf_interlaced ? CSI_FRAME_RAW_8 : CSI_FIELD_RAW_8; 210 case V4L2_PIX_FMT_SBGGR10: 211 case V4L2_PIX_FMT_SGBRG10: 212 case V4L2_PIX_FMT_SGRBG10: 213 case V4L2_PIX_FMT_SRGGB10: 214 return buf_interlaced ? CSI_FRAME_RAW_10 : CSI_FIELD_RAW_10; 215 case V4L2_PIX_FMT_SBGGR12: 216 case V4L2_PIX_FMT_SGBRG12: 217 case V4L2_PIX_FMT_SGRBG12: 218 case V4L2_PIX_FMT_SRGGB12: 219 return buf_interlaced ? CSI_FRAME_RAW_12 : CSI_FIELD_RAW_12; 220 221 case V4L2_PIX_FMT_YUYV: 222 case V4L2_PIX_FMT_YVYU: 223 case V4L2_PIX_FMT_UYVY: 224 case V4L2_PIX_FMT_VYUY: 225 return buf_interlaced ? CSI_FRAME_RAW_8 : CSI_FIELD_RAW_8; 226 227 case V4L2_PIX_FMT_NV12_16L16: 228 return buf_interlaced ? CSI_FRAME_MB_YUV420 : 229 CSI_FIELD_MB_YUV420; 230 case V4L2_PIX_FMT_NV12: 231 case V4L2_PIX_FMT_NV21: 232 return buf_interlaced ? CSI_FRAME_UV_CB_YUV420 : 233 CSI_FIELD_UV_CB_YUV420; 234 case V4L2_PIX_FMT_YUV420: 235 case V4L2_PIX_FMT_YVU420: 236 return buf_interlaced ? CSI_FRAME_PLANAR_YUV420 : 237 CSI_FIELD_PLANAR_YUV420; 238 case V4L2_PIX_FMT_NV16: 239 case V4L2_PIX_FMT_NV61: 240 return buf_interlaced ? CSI_FRAME_UV_CB_YUV422 : 241 CSI_FIELD_UV_CB_YUV422; 242 case V4L2_PIX_FMT_YUV422P: 243 return buf_interlaced ? CSI_FRAME_PLANAR_YUV422 : 244 CSI_FIELD_PLANAR_YUV422; 245 246 case V4L2_PIX_FMT_RGB565: 247 case V4L2_PIX_FMT_RGB565X: 248 return buf_interlaced ? CSI_FRAME_RGB565 : CSI_FIELD_RGB565; 249 250 case V4L2_PIX_FMT_JPEG: 251 return buf_interlaced ? CSI_FRAME_RAW_8 : CSI_FIELD_RAW_8; 252 253 default: 254 dev_warn(csi_dev->dev, "Unsupported pixformat: 0x%x\n", pixformat); 255 break; 256 } 257 258 return CSI_FIELD_RAW_8; 259 } 260 261 static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_device *csi_dev, 262 u32 mbus_code, u32 pixformat) 263 { 264 /* Input sequence does not apply to non-YUV formats */ 265 if ((mbus_code & 0xF000) != 0x2000) 266 return 0; 267 268 switch (pixformat) { 269 case V4L2_PIX_FMT_NV12_16L16: 270 case V4L2_PIX_FMT_NV12: 271 case V4L2_PIX_FMT_NV16: 272 case V4L2_PIX_FMT_YUV420: 273 case V4L2_PIX_FMT_YUV422P: 274 switch (mbus_code) { 275 case MEDIA_BUS_FMT_UYVY8_2X8: 276 case MEDIA_BUS_FMT_UYVY8_1X16: 277 return CSI_INPUT_SEQ_UYVY; 278 case MEDIA_BUS_FMT_VYUY8_2X8: 279 case MEDIA_BUS_FMT_VYUY8_1X16: 280 return CSI_INPUT_SEQ_VYUY; 281 case MEDIA_BUS_FMT_YUYV8_2X8: 282 case MEDIA_BUS_FMT_YUYV8_1X16: 283 return CSI_INPUT_SEQ_YUYV; 284 case MEDIA_BUS_FMT_YVYU8_1X16: 285 case MEDIA_BUS_FMT_YVYU8_2X8: 286 return CSI_INPUT_SEQ_YVYU; 287 default: 288 dev_warn(csi_dev->dev, "Unsupported mbus code: 0x%x\n", 289 mbus_code); 290 break; 291 } 292 break; 293 case V4L2_PIX_FMT_NV21: 294 case V4L2_PIX_FMT_NV61: 295 case V4L2_PIX_FMT_YVU420: 296 switch (mbus_code) { 297 case MEDIA_BUS_FMT_UYVY8_2X8: 298 case MEDIA_BUS_FMT_UYVY8_1X16: 299 return CSI_INPUT_SEQ_VYUY; 300 case MEDIA_BUS_FMT_VYUY8_2X8: 301 case MEDIA_BUS_FMT_VYUY8_1X16: 302 return CSI_INPUT_SEQ_UYVY; 303 case MEDIA_BUS_FMT_YUYV8_2X8: 304 case MEDIA_BUS_FMT_YUYV8_1X16: 305 return CSI_INPUT_SEQ_YVYU; 306 case MEDIA_BUS_FMT_YVYU8_1X16: 307 case MEDIA_BUS_FMT_YVYU8_2X8: 308 return CSI_INPUT_SEQ_YUYV; 309 default: 310 dev_warn(csi_dev->dev, "Unsupported mbus code: 0x%x\n", 311 mbus_code); 312 break; 313 } 314 break; 315 316 case V4L2_PIX_FMT_YUYV: 317 return CSI_INPUT_SEQ_YUYV; 318 319 default: 320 dev_warn(csi_dev->dev, "Unsupported pixformat: 0x%x, defaulting to YUYV\n", 321 pixformat); 322 break; 323 } 324 325 return CSI_INPUT_SEQ_YUYV; 326 } 327 328 static void sun6i_csi_setup_bus(struct sun6i_csi_device *csi_dev) 329 { 330 struct v4l2_fwnode_endpoint *endpoint = &csi_dev->v4l2.v4l2_ep; 331 struct sun6i_csi_config *config = &csi_dev->config; 332 unsigned char bus_width; 333 u32 flags; 334 u32 cfg; 335 bool input_interlaced = false; 336 337 if (config->field == V4L2_FIELD_INTERLACED 338 || config->field == V4L2_FIELD_INTERLACED_TB 339 || config->field == V4L2_FIELD_INTERLACED_BT) 340 input_interlaced = true; 341 342 bus_width = endpoint->bus.parallel.bus_width; 343 344 regmap_read(csi_dev->regmap, CSI_IF_CFG_REG, &cfg); 345 346 cfg &= ~(CSI_IF_CFG_CSI_IF_MASK | CSI_IF_CFG_MIPI_IF_MASK | 347 CSI_IF_CFG_IF_DATA_WIDTH_MASK | 348 CSI_IF_CFG_CLK_POL_MASK | CSI_IF_CFG_VREF_POL_MASK | 349 CSI_IF_CFG_HREF_POL_MASK | CSI_IF_CFG_FIELD_MASK | 350 CSI_IF_CFG_SRC_TYPE_MASK); 351 352 if (input_interlaced) 353 cfg |= CSI_IF_CFG_SRC_TYPE_INTERLACED; 354 else 355 cfg |= CSI_IF_CFG_SRC_TYPE_PROGRESSED; 356 357 switch (endpoint->bus_type) { 358 case V4L2_MBUS_PARALLEL: 359 cfg |= CSI_IF_CFG_MIPI_IF_CSI; 360 361 flags = endpoint->bus.parallel.flags; 362 363 cfg |= (bus_width == 16) ? CSI_IF_CFG_CSI_IF_YUV422_16BIT : 364 CSI_IF_CFG_CSI_IF_YUV422_INTLV; 365 366 if (flags & V4L2_MBUS_FIELD_EVEN_LOW) 367 cfg |= CSI_IF_CFG_FIELD_POSITIVE; 368 369 if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) 370 cfg |= CSI_IF_CFG_VREF_POL_POSITIVE; 371 if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) 372 cfg |= CSI_IF_CFG_HREF_POL_POSITIVE; 373 374 if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) 375 cfg |= CSI_IF_CFG_CLK_POL_FALLING_EDGE; 376 break; 377 case V4L2_MBUS_BT656: 378 cfg |= CSI_IF_CFG_MIPI_IF_CSI; 379 380 flags = endpoint->bus.parallel.flags; 381 382 cfg |= (bus_width == 16) ? CSI_IF_CFG_CSI_IF_BT1120 : 383 CSI_IF_CFG_CSI_IF_BT656; 384 385 if (flags & V4L2_MBUS_FIELD_EVEN_LOW) 386 cfg |= CSI_IF_CFG_FIELD_POSITIVE; 387 388 if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) 389 cfg |= CSI_IF_CFG_CLK_POL_FALLING_EDGE; 390 break; 391 default: 392 dev_warn(csi_dev->dev, "Unsupported bus type: %d\n", 393 endpoint->bus_type); 394 break; 395 } 396 397 switch (bus_width) { 398 case 8: 399 cfg |= CSI_IF_CFG_IF_DATA_WIDTH_8BIT; 400 break; 401 case 10: 402 cfg |= CSI_IF_CFG_IF_DATA_WIDTH_10BIT; 403 break; 404 case 12: 405 cfg |= CSI_IF_CFG_IF_DATA_WIDTH_12BIT; 406 break; 407 case 16: /* No need to configure DATA_WIDTH for 16bit */ 408 break; 409 default: 410 dev_warn(csi_dev->dev, "Unsupported bus width: %u\n", bus_width); 411 break; 412 } 413 414 regmap_write(csi_dev->regmap, CSI_IF_CFG_REG, cfg); 415 } 416 417 static void sun6i_csi_set_format(struct sun6i_csi_device *csi_dev) 418 { 419 struct sun6i_csi_config *config = &csi_dev->config; 420 u32 cfg; 421 u32 val; 422 423 regmap_read(csi_dev->regmap, CSI_CH_CFG_REG, &cfg); 424 425 cfg &= ~(CSI_CH_CFG_INPUT_FMT_MASK | 426 CSI_CH_CFG_OUTPUT_FMT_MASK | CSI_CH_CFG_VFLIP_EN | 427 CSI_CH_CFG_HFLIP_EN | CSI_CH_CFG_FIELD_SEL_MASK | 428 CSI_CH_CFG_INPUT_SEQ_MASK); 429 430 val = get_csi_input_format(csi_dev, config->code, 431 config->pixelformat); 432 cfg |= CSI_CH_CFG_INPUT_FMT(val); 433 434 val = get_csi_output_format(csi_dev, config->pixelformat, 435 config->field); 436 cfg |= CSI_CH_CFG_OUTPUT_FMT(val); 437 438 val = get_csi_input_seq(csi_dev, config->code, 439 config->pixelformat); 440 cfg |= CSI_CH_CFG_INPUT_SEQ(val); 441 442 if (config->field == V4L2_FIELD_TOP) 443 cfg |= CSI_CH_CFG_FIELD_SEL_FIELD0; 444 else if (config->field == V4L2_FIELD_BOTTOM) 445 cfg |= CSI_CH_CFG_FIELD_SEL_FIELD1; 446 else 447 cfg |= CSI_CH_CFG_FIELD_SEL_BOTH; 448 449 regmap_write(csi_dev->regmap, CSI_CH_CFG_REG, cfg); 450 } 451 452 static void sun6i_csi_set_window(struct sun6i_csi_device *csi_dev) 453 { 454 struct sun6i_csi_config *config = &csi_dev->config; 455 u32 bytesperline_y; 456 u32 bytesperline_c; 457 int *planar_offset = csi_dev->planar_offset; 458 u32 width = config->width; 459 u32 height = config->height; 460 u32 hor_len = width; 461 462 switch (config->pixelformat) { 463 case V4L2_PIX_FMT_YUYV: 464 case V4L2_PIX_FMT_YVYU: 465 case V4L2_PIX_FMT_UYVY: 466 case V4L2_PIX_FMT_VYUY: 467 dev_dbg(csi_dev->dev, 468 "Horizontal length should be 2 times of width for packed YUV formats!\n"); 469 hor_len = width * 2; 470 break; 471 default: 472 break; 473 } 474 475 regmap_write(csi_dev->regmap, CSI_CH_HSIZE_REG, 476 CSI_CH_HSIZE_HOR_LEN(hor_len) | 477 CSI_CH_HSIZE_HOR_START(0)); 478 regmap_write(csi_dev->regmap, CSI_CH_VSIZE_REG, 479 CSI_CH_VSIZE_VER_LEN(height) | 480 CSI_CH_VSIZE_VER_START(0)); 481 482 planar_offset[0] = 0; 483 switch (config->pixelformat) { 484 case V4L2_PIX_FMT_NV12_16L16: 485 case V4L2_PIX_FMT_NV12: 486 case V4L2_PIX_FMT_NV21: 487 case V4L2_PIX_FMT_NV16: 488 case V4L2_PIX_FMT_NV61: 489 bytesperline_y = width; 490 bytesperline_c = width; 491 planar_offset[1] = bytesperline_y * height; 492 planar_offset[2] = -1; 493 break; 494 case V4L2_PIX_FMT_YUV420: 495 case V4L2_PIX_FMT_YVU420: 496 bytesperline_y = width; 497 bytesperline_c = width / 2; 498 planar_offset[1] = bytesperline_y * height; 499 planar_offset[2] = planar_offset[1] + 500 bytesperline_c * height / 2; 501 break; 502 case V4L2_PIX_FMT_YUV422P: 503 bytesperline_y = width; 504 bytesperline_c = width / 2; 505 planar_offset[1] = bytesperline_y * height; 506 planar_offset[2] = planar_offset[1] + 507 bytesperline_c * height; 508 break; 509 default: /* raw */ 510 dev_dbg(csi_dev->dev, 511 "Calculating pixelformat(0x%x)'s bytesperline as a packed format\n", 512 config->pixelformat); 513 bytesperline_y = (sun6i_csi_get_bpp(config->pixelformat) * 514 config->width) / 8; 515 bytesperline_c = 0; 516 planar_offset[1] = -1; 517 planar_offset[2] = -1; 518 break; 519 } 520 521 regmap_write(csi_dev->regmap, CSI_CH_BUF_LEN_REG, 522 CSI_CH_BUF_LEN_BUF_LEN_C(bytesperline_c) | 523 CSI_CH_BUF_LEN_BUF_LEN_Y(bytesperline_y)); 524 } 525 526 int sun6i_csi_update_config(struct sun6i_csi_device *csi_dev, 527 struct sun6i_csi_config *config) 528 { 529 if (!config) 530 return -EINVAL; 531 532 memcpy(&csi_dev->config, config, sizeof(csi_dev->config)); 533 534 sun6i_csi_setup_bus(csi_dev); 535 sun6i_csi_set_format(csi_dev); 536 sun6i_csi_set_window(csi_dev); 537 538 return 0; 539 } 540 541 void sun6i_csi_update_buf_addr(struct sun6i_csi_device *csi_dev, 542 dma_addr_t addr) 543 { 544 regmap_write(csi_dev->regmap, CSI_CH_F0_BUFA_REG, 545 (addr + csi_dev->planar_offset[0]) >> 2); 546 if (csi_dev->planar_offset[1] != -1) 547 regmap_write(csi_dev->regmap, CSI_CH_F1_BUFA_REG, 548 (addr + csi_dev->planar_offset[1]) >> 2); 549 if (csi_dev->planar_offset[2] != -1) 550 regmap_write(csi_dev->regmap, CSI_CH_F2_BUFA_REG, 551 (addr + csi_dev->planar_offset[2]) >> 2); 552 } 553 554 void sun6i_csi_set_stream(struct sun6i_csi_device *csi_dev, bool enable) 555 { 556 struct regmap *regmap = csi_dev->regmap; 557 558 if (!enable) { 559 regmap_update_bits(regmap, CSI_CAP_REG, CSI_CAP_CH0_VCAP_ON, 0); 560 regmap_write(regmap, CSI_CH_INT_EN_REG, 0); 561 return; 562 } 563 564 regmap_write(regmap, CSI_CH_INT_STA_REG, 0xFF); 565 regmap_write(regmap, CSI_CH_INT_EN_REG, 566 CSI_CH_INT_EN_HB_OF_INT_EN | 567 CSI_CH_INT_EN_FIFO2_OF_INT_EN | 568 CSI_CH_INT_EN_FIFO1_OF_INT_EN | 569 CSI_CH_INT_EN_FIFO0_OF_INT_EN | 570 CSI_CH_INT_EN_FD_INT_EN | 571 CSI_CH_INT_EN_CD_INT_EN); 572 573 regmap_update_bits(regmap, CSI_CAP_REG, CSI_CAP_CH0_VCAP_ON, 574 CSI_CAP_CH0_VCAP_ON); 575 } 576 577 /* V4L2 */ 578 579 static int sun6i_csi_link_entity(struct sun6i_csi_device *csi_dev, 580 struct media_entity *entity, 581 struct fwnode_handle *fwnode) 582 { 583 struct media_entity *sink; 584 struct media_pad *sink_pad; 585 int src_pad_index; 586 int ret; 587 588 ret = media_entity_get_fwnode_pad(entity, fwnode, MEDIA_PAD_FL_SOURCE); 589 if (ret < 0) { 590 dev_err(csi_dev->dev, 591 "%s: no source pad in external entity %s\n", __func__, 592 entity->name); 593 return -EINVAL; 594 } 595 596 src_pad_index = ret; 597 598 sink = &csi_dev->video.video_dev.entity; 599 sink_pad = &csi_dev->video.pad; 600 601 dev_dbg(csi_dev->dev, "creating %s:%u -> %s:%u link\n", 602 entity->name, src_pad_index, sink->name, sink_pad->index); 603 ret = media_create_pad_link(entity, src_pad_index, sink, 604 sink_pad->index, 605 MEDIA_LNK_FL_ENABLED | 606 MEDIA_LNK_FL_IMMUTABLE); 607 if (ret < 0) { 608 dev_err(csi_dev->dev, "failed to create %s:%u -> %s:%u link\n", 609 entity->name, src_pad_index, 610 sink->name, sink_pad->index); 611 return ret; 612 } 613 614 return 0; 615 } 616 617 static int sun6i_subdev_notify_complete(struct v4l2_async_notifier *notifier) 618 { 619 struct sun6i_csi_device *csi_dev = 620 container_of(notifier, struct sun6i_csi_device, 621 v4l2.notifier); 622 struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; 623 struct v4l2_device *v4l2_dev = &v4l2->v4l2_dev; 624 struct v4l2_subdev *sd; 625 int ret; 626 627 dev_dbg(csi_dev->dev, "notify complete, all subdevs registered\n"); 628 629 sd = list_first_entry(&v4l2_dev->subdevs, struct v4l2_subdev, list); 630 if (!sd) 631 return -EINVAL; 632 633 ret = sun6i_csi_link_entity(csi_dev, &sd->entity, sd->fwnode); 634 if (ret < 0) 635 return ret; 636 637 ret = v4l2_device_register_subdev_nodes(v4l2_dev); 638 if (ret < 0) 639 return ret; 640 641 return 0; 642 } 643 644 static const struct v4l2_async_notifier_operations sun6i_csi_async_ops = { 645 .complete = sun6i_subdev_notify_complete, 646 }; 647 648 static int sun6i_csi_fwnode_parse(struct device *dev, 649 struct v4l2_fwnode_endpoint *vep, 650 struct v4l2_async_subdev *asd) 651 { 652 struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev); 653 654 if (vep->base.port || vep->base.id) { 655 dev_warn(dev, "Only support a single port with one endpoint\n"); 656 return -ENOTCONN; 657 } 658 659 switch (vep->bus_type) { 660 case V4L2_MBUS_PARALLEL: 661 case V4L2_MBUS_BT656: 662 csi_dev->v4l2.v4l2_ep = *vep; 663 return 0; 664 default: 665 dev_err(dev, "Unsupported media bus type\n"); 666 return -ENOTCONN; 667 } 668 } 669 670 static int sun6i_csi_v4l2_setup(struct sun6i_csi_device *csi_dev) 671 { 672 struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; 673 struct media_device *media_dev = &v4l2->media_dev; 674 struct v4l2_device *v4l2_dev = &v4l2->v4l2_dev; 675 struct v4l2_async_notifier *notifier = &v4l2->notifier; 676 struct device *dev = csi_dev->dev; 677 int ret; 678 679 /* Media Device */ 680 681 strscpy(media_dev->model, SUN6I_CSI_DESCRIPTION, 682 sizeof(media_dev->model)); 683 media_dev->hw_revision = 0; 684 media_dev->dev = dev; 685 686 media_device_init(media_dev); 687 688 ret = media_device_register(media_dev); 689 if (ret) { 690 dev_err(dev, "failed to register media device: %d\n", ret); 691 goto error_media; 692 } 693 694 /* V4L2 Control Handler */ 695 696 ret = v4l2_ctrl_handler_init(&v4l2->ctrl_handler, 0); 697 if (ret) { 698 dev_err(dev, "failed to init v4l2 control handler: %d\n", ret); 699 goto error_media; 700 } 701 702 /* V4L2 Device */ 703 704 v4l2_dev->mdev = media_dev; 705 v4l2_dev->ctrl_handler = &v4l2->ctrl_handler; 706 707 ret = v4l2_device_register(dev, v4l2_dev); 708 if (ret) { 709 dev_err(dev, "failed to register v4l2 device: %d\n", ret); 710 goto error_v4l2_ctrl; 711 } 712 713 /* Video */ 714 715 ret = sun6i_video_setup(csi_dev); 716 if (ret) 717 goto error_v4l2_device; 718 719 /* V4L2 Async */ 720 721 v4l2_async_nf_init(notifier); 722 notifier->ops = &sun6i_csi_async_ops; 723 724 ret = v4l2_async_nf_parse_fwnode_endpoints(dev, notifier, 725 sizeof(struct 726 v4l2_async_subdev), 727 sun6i_csi_fwnode_parse); 728 if (ret) 729 goto error_video; 730 731 ret = v4l2_async_nf_register(v4l2_dev, notifier); 732 if (ret) { 733 dev_err(dev, "failed to register v4l2 async notifier: %d\n", 734 ret); 735 goto error_v4l2_async_notifier; 736 } 737 738 return 0; 739 740 error_v4l2_async_notifier: 741 v4l2_async_nf_cleanup(notifier); 742 743 error_video: 744 sun6i_video_cleanup(csi_dev); 745 746 error_v4l2_device: 747 v4l2_device_unregister(&v4l2->v4l2_dev); 748 749 error_v4l2_ctrl: 750 v4l2_ctrl_handler_free(&v4l2->ctrl_handler); 751 752 error_media: 753 media_device_unregister(media_dev); 754 media_device_cleanup(media_dev); 755 756 return ret; 757 } 758 759 static void sun6i_csi_v4l2_cleanup(struct sun6i_csi_device *csi_dev) 760 { 761 struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; 762 763 media_device_unregister(&v4l2->media_dev); 764 v4l2_async_nf_unregister(&v4l2->notifier); 765 v4l2_async_nf_cleanup(&v4l2->notifier); 766 sun6i_video_cleanup(csi_dev); 767 v4l2_device_unregister(&v4l2->v4l2_dev); 768 v4l2_ctrl_handler_free(&v4l2->ctrl_handler); 769 media_device_cleanup(&v4l2->media_dev); 770 } 771 772 /* Platform */ 773 774 static irqreturn_t sun6i_csi_interrupt(int irq, void *private) 775 { 776 struct sun6i_csi_device *csi_dev = private; 777 struct regmap *regmap = csi_dev->regmap; 778 u32 status; 779 780 regmap_read(regmap, CSI_CH_INT_STA_REG, &status); 781 782 if (!(status & 0xFF)) 783 return IRQ_NONE; 784 785 if ((status & CSI_CH_INT_STA_FIFO0_OF_PD) || 786 (status & CSI_CH_INT_STA_FIFO1_OF_PD) || 787 (status & CSI_CH_INT_STA_FIFO2_OF_PD) || 788 (status & CSI_CH_INT_STA_HB_OF_PD)) { 789 regmap_write(regmap, CSI_CH_INT_STA_REG, status); 790 regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0); 791 regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 792 CSI_EN_CSI_EN); 793 return IRQ_HANDLED; 794 } 795 796 if (status & CSI_CH_INT_STA_FD_PD) 797 sun6i_video_frame_done(csi_dev); 798 799 regmap_write(regmap, CSI_CH_INT_STA_REG, status); 800 801 return IRQ_HANDLED; 802 } 803 804 static int sun6i_csi_suspend(struct device *dev) 805 { 806 struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev); 807 808 reset_control_assert(csi_dev->reset); 809 clk_disable_unprepare(csi_dev->clock_ram); 810 clk_disable_unprepare(csi_dev->clock_mod); 811 812 return 0; 813 } 814 815 static int sun6i_csi_resume(struct device *dev) 816 { 817 struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev); 818 int ret; 819 820 ret = reset_control_deassert(csi_dev->reset); 821 if (ret) { 822 dev_err(dev, "failed to deassert reset\n"); 823 return ret; 824 } 825 826 ret = clk_prepare_enable(csi_dev->clock_mod); 827 if (ret) { 828 dev_err(dev, "failed to enable module clock\n"); 829 goto error_reset; 830 } 831 832 ret = clk_prepare_enable(csi_dev->clock_ram); 833 if (ret) { 834 dev_err(dev, "failed to enable ram clock\n"); 835 goto error_clock_mod; 836 } 837 838 return 0; 839 840 error_clock_mod: 841 clk_disable_unprepare(csi_dev->clock_mod); 842 843 error_reset: 844 reset_control_assert(csi_dev->reset); 845 846 return ret; 847 } 848 849 static const struct dev_pm_ops sun6i_csi_pm_ops = { 850 .runtime_suspend = sun6i_csi_suspend, 851 .runtime_resume = sun6i_csi_resume, 852 }; 853 854 static const struct regmap_config sun6i_csi_regmap_config = { 855 .reg_bits = 32, 856 .reg_stride = 4, 857 .val_bits = 32, 858 .max_register = 0x9c, 859 }; 860 861 static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev, 862 struct platform_device *platform_dev) 863 { 864 struct device *dev = csi_dev->dev; 865 const struct sun6i_csi_variant *variant; 866 void __iomem *io_base; 867 int ret; 868 int irq; 869 870 variant = of_device_get_match_data(dev); 871 if (!variant) 872 return -EINVAL; 873 874 /* Registers */ 875 876 io_base = devm_platform_ioremap_resource(platform_dev, 0); 877 if (IS_ERR(io_base)) 878 return PTR_ERR(io_base); 879 880 csi_dev->regmap = devm_regmap_init_mmio_clk(dev, "bus", io_base, 881 &sun6i_csi_regmap_config); 882 if (IS_ERR(csi_dev->regmap)) { 883 dev_err(dev, "failed to init register map\n"); 884 return PTR_ERR(csi_dev->regmap); 885 } 886 887 /* Clocks */ 888 889 csi_dev->clock_mod = devm_clk_get(dev, "mod"); 890 if (IS_ERR(csi_dev->clock_mod)) { 891 dev_err(dev, "failed to acquire module clock\n"); 892 return PTR_ERR(csi_dev->clock_mod); 893 } 894 895 csi_dev->clock_ram = devm_clk_get(dev, "ram"); 896 if (IS_ERR(csi_dev->clock_ram)) { 897 dev_err(dev, "failed to acquire ram clock\n"); 898 return PTR_ERR(csi_dev->clock_ram); 899 } 900 901 ret = clk_set_rate_exclusive(csi_dev->clock_mod, 902 variant->clock_mod_rate); 903 if (ret) { 904 dev_err(dev, "failed to set mod clock rate\n"); 905 return ret; 906 } 907 908 /* Reset */ 909 910 csi_dev->reset = devm_reset_control_get_shared(dev, NULL); 911 if (IS_ERR(csi_dev->reset)) { 912 dev_err(dev, "failed to acquire reset\n"); 913 ret = PTR_ERR(csi_dev->reset); 914 goto error_clock_rate_exclusive; 915 } 916 917 /* Interrupt */ 918 919 irq = platform_get_irq(platform_dev, 0); 920 if (irq < 0) { 921 dev_err(dev, "failed to get interrupt\n"); 922 ret = -ENXIO; 923 goto error_clock_rate_exclusive; 924 } 925 926 ret = devm_request_irq(dev, irq, sun6i_csi_interrupt, 0, SUN6I_CSI_NAME, 927 csi_dev); 928 if (ret) { 929 dev_err(dev, "failed to request interrupt\n"); 930 goto error_clock_rate_exclusive; 931 } 932 933 /* Runtime PM */ 934 935 pm_runtime_enable(dev); 936 937 return 0; 938 939 error_clock_rate_exclusive: 940 clk_rate_exclusive_put(csi_dev->clock_mod); 941 942 return ret; 943 } 944 945 static void sun6i_csi_resources_cleanup(struct sun6i_csi_device *csi_dev) 946 { 947 pm_runtime_disable(csi_dev->dev); 948 clk_rate_exclusive_put(csi_dev->clock_mod); 949 } 950 951 static int sun6i_csi_probe(struct platform_device *platform_dev) 952 { 953 struct sun6i_csi_device *csi_dev; 954 struct device *dev = &platform_dev->dev; 955 int ret; 956 957 csi_dev = devm_kzalloc(dev, sizeof(*csi_dev), GFP_KERNEL); 958 if (!csi_dev) 959 return -ENOMEM; 960 961 csi_dev->dev = &platform_dev->dev; 962 platform_set_drvdata(platform_dev, csi_dev); 963 964 ret = sun6i_csi_resources_setup(csi_dev, platform_dev); 965 if (ret) 966 return ret; 967 968 ret = sun6i_csi_v4l2_setup(csi_dev); 969 if (ret) 970 goto error_resources; 971 972 return 0; 973 974 error_resources: 975 sun6i_csi_resources_cleanup(csi_dev); 976 977 return ret; 978 } 979 980 static int sun6i_csi_remove(struct platform_device *pdev) 981 { 982 struct sun6i_csi_device *csi_dev = platform_get_drvdata(pdev); 983 984 sun6i_csi_v4l2_cleanup(csi_dev); 985 sun6i_csi_resources_cleanup(csi_dev); 986 987 return 0; 988 } 989 990 static const struct sun6i_csi_variant sun6i_a31_csi_variant = { 991 .clock_mod_rate = 297000000, 992 }; 993 994 static const struct sun6i_csi_variant sun50i_a64_csi_variant = { 995 .clock_mod_rate = 300000000, 996 }; 997 998 static const struct of_device_id sun6i_csi_of_match[] = { 999 { 1000 .compatible = "allwinner,sun6i-a31-csi", 1001 .data = &sun6i_a31_csi_variant, 1002 }, 1003 { 1004 .compatible = "allwinner,sun8i-a83t-csi", 1005 .data = &sun6i_a31_csi_variant, 1006 }, 1007 { 1008 .compatible = "allwinner,sun8i-h3-csi", 1009 .data = &sun6i_a31_csi_variant, 1010 }, 1011 { 1012 .compatible = "allwinner,sun8i-v3s-csi", 1013 .data = &sun6i_a31_csi_variant, 1014 }, 1015 { 1016 .compatible = "allwinner,sun50i-a64-csi", 1017 .data = &sun50i_a64_csi_variant, 1018 }, 1019 {}, 1020 }; 1021 1022 MODULE_DEVICE_TABLE(of, sun6i_csi_of_match); 1023 1024 static struct platform_driver sun6i_csi_platform_driver = { 1025 .probe = sun6i_csi_probe, 1026 .remove = sun6i_csi_remove, 1027 .driver = { 1028 .name = SUN6I_CSI_NAME, 1029 .of_match_table = of_match_ptr(sun6i_csi_of_match), 1030 .pm = &sun6i_csi_pm_ops, 1031 }, 1032 }; 1033 1034 module_platform_driver(sun6i_csi_platform_driver); 1035 1036 MODULE_DESCRIPTION("Allwinner A31 Camera Sensor Interface driver"); 1037 MODULE_AUTHOR("Yong Deng <yong.deng@magewell.com>"); 1038 MODULE_LICENSE("GPL"); 1039