633 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * IMI RDACM21 GMSL Camera Driver4 *5 * Copyright (C) 2017-2020 Jacopo Mondi6 * Copyright (C) 2017-2019 Kieran Bingham7 * Copyright (C) 2017-2019 Laurent Pinchart8 * Copyright (C) 2017-2019 Niklas Söderlund9 * Copyright (C) 2016 Renesas Electronics Corporation10 * Copyright (C) 2015 Cogent Embedded, Inc.11 */12 13#include <linux/delay.h>14#include <linux/fwnode.h>15#include <linux/init.h>16#include <linux/i2c.h>17#include <linux/module.h>18#include <linux/slab.h>19#include <linux/videodev2.h>20 21#include <media/v4l2-async.h>22#include <media/v4l2-ctrls.h>23#include <media/v4l2-subdev.h>24#include "max9271.h"25 26#define MAX9271_RESET_CYCLES 1027 28#define OV490_I2C_ADDRESS 0x2429 30#define OV490_PAGE_HIGH_REG 0xfffd31#define OV490_PAGE_LOW_REG 0xfffe32 33/*34 * The SCCB slave handling is undocumented; the registers naming scheme is35 * totally arbitrary.36 */37#define OV490_SCCB_SLAVE_WRITE 0x0038#define OV490_SCCB_SLAVE_READ 0x0139#define OV490_SCCB_SLAVE0_DIR 0x8019500040#define OV490_SCCB_SLAVE0_ADDR_HIGH 0x8019500141#define OV490_SCCB_SLAVE0_ADDR_LOW 0x8019500242 43#define OV490_DVP_CTRL3 0x8028600944 45#define OV490_ODS_CTRL_FRAME_OUTPUT_EN 0x0c46#define OV490_ODS_CTRL 0x8029d00047 48#define OV490_HOST_CMD 0x808000c049#define OV490_HOST_CMD_TRIGGER 0xc150 51#define OV490_ID_VAL 0x049052#define OV490_ID(_p, _v) ((((_p) & 0xff) << 8) | ((_v) & 0xff))53#define OV490_PID 0x8080300a54#define OV490_VER 0x8080300b55#define OV490_PID_TIMEOUT 2056#define OV490_OUTPUT_EN_TIMEOUT 30057 58#define OV490_GPIO0 BIT(0)59#define OV490_SPWDN0 BIT(0)60#define OV490_GPIO_SEL0 0x8080005061#define OV490_GPIO_SEL1 0x8080005162#define OV490_GPIO_DIRECTION0 0x8080005463#define OV490_GPIO_DIRECTION1 0x8080005564#define OV490_GPIO_OUTPUT_VALUE0 0x8080005865#define OV490_GPIO_OUTPUT_VALUE1 0x8080005966 67#define OV490_ISP_HSIZE_LOW 0x8082006068#define OV490_ISP_HSIZE_HIGH 0x8082006169#define OV490_ISP_VSIZE_LOW 0x8082006270#define OV490_ISP_VSIZE_HIGH 0x8082006371 72#define OV10640_PID_TIMEOUT 2073#define OV10640_ID_HIGH 0xa674#define OV10640_CHIP_ID 0x300a75#define OV10640_PIXEL_RATE 5500000076 77struct rdacm21_device {78 struct device *dev;79 struct max9271_device serializer;80 struct i2c_client *isp;81 struct v4l2_subdev sd;82 struct media_pad pad;83 struct v4l2_mbus_framefmt fmt;84 struct v4l2_ctrl_handler ctrls;85 u32 addrs[2];86 u16 last_page;87};88 89static inline struct rdacm21_device *sd_to_rdacm21(struct v4l2_subdev *sd)90{91 return container_of(sd, struct rdacm21_device, sd);92}93 94static const struct ov490_reg {95 u16 reg;96 u8 val;97} ov490_regs_wizard[] = {98 {0xfffd, 0x80},99 {0xfffe, 0x82},100 {0x0071, 0x11},101 {0x0075, 0x11},102 {0xfffe, 0x29},103 {0x6010, 0x01},104 /*105 * OV490 EMB line disable in YUV and RAW data,106 * NOTE: EMB line is still used in ISP and sensor107 */108 {0xe000, 0x14},109 {0xfffe, 0x28},110 {0x6000, 0x04},111 {0x6004, 0x00},112 /*113 * PCLK polarity - useless due to silicon bug.114 * Use 0x808000bb register instead.115 */116 {0x6008, 0x00},117 {0xfffe, 0x80},118 {0x0091, 0x00},119 /* bit[3]=0 - PCLK polarity workaround. */120 {0x00bb, 0x1d},121 /* Ov490 FSIN: app_fsin_from_fsync */122 {0xfffe, 0x85},123 {0x0008, 0x00},124 {0x0009, 0x01},125 /* FSIN0 source. */126 {0x000A, 0x05},127 {0x000B, 0x00},128 /* FSIN0 delay. */129 {0x0030, 0x02},130 {0x0031, 0x00},131 {0x0032, 0x00},132 {0x0033, 0x00},133 /* FSIN1 delay. */134 {0x0038, 0x02},135 {0x0039, 0x00},136 {0x003A, 0x00},137 {0x003B, 0x00},138 /* FSIN0 length. */139 {0x0070, 0x2C},140 {0x0071, 0x01},141 {0x0072, 0x00},142 {0x0073, 0x00},143 /* FSIN1 length. */144 {0x0074, 0x64},145 {0x0075, 0x00},146 {0x0076, 0x00},147 {0x0077, 0x00},148 {0x0000, 0x14},149 {0x0001, 0x00},150 {0x0002, 0x00},151 {0x0003, 0x00},152 /*153 * Load fsin0,load fsin1,load other,154 * It will be cleared automatically.155 */156 {0x0004, 0x32},157 {0x0005, 0x00},158 {0x0006, 0x00},159 {0x0007, 0x00},160 {0xfffe, 0x80},161 /* Sensor FSIN. */162 {0x0081, 0x00},163 /* ov10640 FSIN enable */164 {0xfffe, 0x19},165 {0x5000, 0x00},166 {0x5001, 0x30},167 {0x5002, 0x8c},168 {0x5003, 0xb2},169 {0xfffe, 0x80},170 {0x00c0, 0xc1},171 /* ov10640 HFLIP=1 by default */172 {0xfffe, 0x19},173 {0x5000, 0x01},174 {0x5001, 0x00},175 {0xfffe, 0x80},176 {0x00c0, 0xdc},177};178 179static int ov490_read(struct rdacm21_device *dev, u16 reg, u8 *val)180{181 u8 buf[2] = { reg >> 8, reg };182 int ret;183 184 ret = i2c_master_send(dev->isp, buf, 2);185 if (ret == 2)186 ret = i2c_master_recv(dev->isp, val, 1);187 188 if (ret < 0) {189 dev_dbg(dev->dev, "%s: register 0x%04x read failed (%d)\n",190 __func__, reg, ret);191 return ret;192 }193 194 return 0;195}196 197static int ov490_write(struct rdacm21_device *dev, u16 reg, u8 val)198{199 u8 buf[3] = { reg >> 8, reg, val };200 int ret;201 202 ret = i2c_master_send(dev->isp, buf, 3);203 if (ret < 0) {204 dev_err(dev->dev, "%s: register 0x%04x write failed (%d)\n",205 __func__, reg, ret);206 return ret;207 }208 209 return 0;210}211 212static int ov490_set_page(struct rdacm21_device *dev, u16 page)213{214 u8 page_high = page >> 8;215 u8 page_low = page;216 int ret;217 218 if (page == dev->last_page)219 return 0;220 221 if (page_high != (dev->last_page >> 8)) {222 ret = ov490_write(dev, OV490_PAGE_HIGH_REG, page_high);223 if (ret)224 return ret;225 }226 227 if (page_low != (u8)dev->last_page) {228 ret = ov490_write(dev, OV490_PAGE_LOW_REG, page_low);229 if (ret)230 return ret;231 }232 233 dev->last_page = page;234 usleep_range(100, 150);235 236 return 0;237}238 239static int ov490_read_reg(struct rdacm21_device *dev, u32 reg, u8 *val)240{241 int ret;242 243 ret = ov490_set_page(dev, reg >> 16);244 if (ret)245 return ret;246 247 ret = ov490_read(dev, (u16)reg, val);248 if (ret)249 return ret;250 251 dev_dbg(dev->dev, "%s: 0x%08x = 0x%02x\n", __func__, reg, *val);252 253 return 0;254}255 256static int ov490_write_reg(struct rdacm21_device *dev, u32 reg, u8 val)257{258 int ret;259 260 ret = ov490_set_page(dev, reg >> 16);261 if (ret)262 return ret;263 264 ret = ov490_write(dev, (u16)reg, val);265 if (ret)266 return ret;267 268 dev_dbg(dev->dev, "%s: 0x%08x = 0x%02x\n", __func__, reg, val);269 270 return 0;271}272 273static int rdacm21_s_stream(struct v4l2_subdev *sd, int enable)274{275 struct rdacm21_device *dev = sd_to_rdacm21(sd);276 277 /*278 * Enable serial link now that the ISP provides a valid pixel clock279 * to start serializing video data on the GMSL link.280 */281 return max9271_set_serial_link(&dev->serializer, enable);282}283 284static int rdacm21_enum_mbus_code(struct v4l2_subdev *sd,285 struct v4l2_subdev_state *sd_state,286 struct v4l2_subdev_mbus_code_enum *code)287{288 if (code->pad || code->index > 0)289 return -EINVAL;290 291 code->code = MEDIA_BUS_FMT_YUYV8_1X16;292 293 return 0;294}295 296static int rdacm21_get_fmt(struct v4l2_subdev *sd,297 struct v4l2_subdev_state *sd_state,298 struct v4l2_subdev_format *format)299{300 struct v4l2_mbus_framefmt *mf = &format->format;301 struct rdacm21_device *dev = sd_to_rdacm21(sd);302 303 if (format->pad)304 return -EINVAL;305 306 mf->width = dev->fmt.width;307 mf->height = dev->fmt.height;308 mf->code = MEDIA_BUS_FMT_YUYV8_1X16;309 mf->colorspace = V4L2_COLORSPACE_SRGB;310 mf->field = V4L2_FIELD_NONE;311 mf->ycbcr_enc = V4L2_YCBCR_ENC_601;312 mf->quantization = V4L2_QUANTIZATION_FULL_RANGE;313 mf->xfer_func = V4L2_XFER_FUNC_NONE;314 315 return 0;316}317 318static const struct v4l2_subdev_video_ops rdacm21_video_ops = {319 .s_stream = rdacm21_s_stream,320};321 322static const struct v4l2_subdev_pad_ops rdacm21_subdev_pad_ops = {323 .enum_mbus_code = rdacm21_enum_mbus_code,324 .get_fmt = rdacm21_get_fmt,325 .set_fmt = rdacm21_get_fmt,326};327 328static const struct v4l2_subdev_ops rdacm21_subdev_ops = {329 .video = &rdacm21_video_ops,330 .pad = &rdacm21_subdev_pad_ops,331};332 333static void ov10640_power_up(struct rdacm21_device *dev)334{335 /* Enable GPIO0#0 (reset) and GPIO1#0 (pwdn) as output lines. */336 ov490_write_reg(dev, OV490_GPIO_SEL0, OV490_GPIO0);337 ov490_write_reg(dev, OV490_GPIO_SEL1, OV490_SPWDN0);338 ov490_write_reg(dev, OV490_GPIO_DIRECTION0, OV490_GPIO0);339 ov490_write_reg(dev, OV490_GPIO_DIRECTION1, OV490_SPWDN0);340 341 /* Power up OV10640 and then reset it. */342 ov490_write_reg(dev, OV490_GPIO_OUTPUT_VALUE1, OV490_SPWDN0);343 usleep_range(1500, 3000);344 345 ov490_write_reg(dev, OV490_GPIO_OUTPUT_VALUE0, 0x00);346 usleep_range(1500, 3000);347 ov490_write_reg(dev, OV490_GPIO_OUTPUT_VALUE0, OV490_GPIO0);348 usleep_range(3000, 5000);349}350 351static int ov10640_check_id(struct rdacm21_device *dev)352{353 unsigned int i;354 u8 val = 0;355 356 /* Read OV10640 ID to test communications. */357 for (i = 0; i < OV10640_PID_TIMEOUT; ++i) {358 ov490_write_reg(dev, OV490_SCCB_SLAVE0_DIR,359 OV490_SCCB_SLAVE_READ);360 ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_HIGH,361 OV10640_CHIP_ID >> 8);362 ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_LOW,363 OV10640_CHIP_ID & 0xff);364 365 /*366 * Trigger SCCB slave transaction and give it some time367 * to complete.368 */369 ov490_write_reg(dev, OV490_HOST_CMD, OV490_HOST_CMD_TRIGGER);370 usleep_range(1000, 1500);371 372 ov490_read_reg(dev, OV490_SCCB_SLAVE0_DIR, &val);373 if (val == OV10640_ID_HIGH)374 break;375 usleep_range(1000, 1500);376 }377 if (i == OV10640_PID_TIMEOUT) {378 dev_err(dev->dev, "OV10640 ID mismatch: (0x%02x)\n", val);379 return -ENODEV;380 }381 382 dev_dbg(dev->dev, "OV10640 ID = 0x%2x\n", val);383 384 return 0;385}386 387static int ov490_initialize(struct rdacm21_device *dev)388{389 u8 pid, ver, val;390 unsigned int i;391 int ret;392 393 ov10640_power_up(dev);394 395 /*396 * Read OV490 Id to test communications. Give it up to 40msec to397 * exit from reset.398 */399 for (i = 0; i < OV490_PID_TIMEOUT; ++i) {400 ret = ov490_read_reg(dev, OV490_PID, &pid);401 if (ret == 0)402 break;403 usleep_range(1000, 2000);404 }405 if (i == OV490_PID_TIMEOUT) {406 dev_err(dev->dev, "OV490 PID read failed (%d)\n", ret);407 return ret;408 }409 410 ret = ov490_read_reg(dev, OV490_VER, &ver);411 if (ret < 0)412 return ret;413 414 if (OV490_ID(pid, ver) != OV490_ID_VAL) {415 dev_err(dev->dev, "OV490 ID mismatch (0x%04x)\n",416 OV490_ID(pid, ver));417 return -ENODEV;418 }419 420 /* Wait for firmware boot by reading streamon status. */421 for (i = 0; i < OV490_OUTPUT_EN_TIMEOUT; ++i) {422 ov490_read_reg(dev, OV490_ODS_CTRL, &val);423 if (val == OV490_ODS_CTRL_FRAME_OUTPUT_EN)424 break;425 usleep_range(1000, 2000);426 }427 if (i == OV490_OUTPUT_EN_TIMEOUT) {428 dev_err(dev->dev, "Timeout waiting for firmware boot\n");429 return -ENODEV;430 }431 432 ret = ov10640_check_id(dev);433 if (ret)434 return ret;435 436 /* Program OV490 with register-value table. */437 for (i = 0; i < ARRAY_SIZE(ov490_regs_wizard); ++i) {438 ret = ov490_write(dev, ov490_regs_wizard[i].reg,439 ov490_regs_wizard[i].val);440 if (ret < 0) {441 dev_err(dev->dev,442 "%s: register %u (0x%04x) write failed (%d)\n",443 __func__, i, ov490_regs_wizard[i].reg, ret);444 445 return -EIO;446 }447 448 usleep_range(100, 150);449 }450 451 /*452 * The ISP is programmed with the content of a serial flash memory.453 * Read the firmware configuration to reflect it through the V4L2 APIs.454 */455 ov490_read_reg(dev, OV490_ISP_HSIZE_HIGH, &val);456 dev->fmt.width = (val & 0xf) << 8;457 ov490_read_reg(dev, OV490_ISP_HSIZE_LOW, &val);458 dev->fmt.width |= (val & 0xff);459 460 ov490_read_reg(dev, OV490_ISP_VSIZE_HIGH, &val);461 dev->fmt.height = (val & 0xf) << 8;462 ov490_read_reg(dev, OV490_ISP_VSIZE_LOW, &val);463 dev->fmt.height |= val & 0xff;464 465 /* Set bus width to 12 bits with [0:11] ordering. */466 ov490_write_reg(dev, OV490_DVP_CTRL3, 0x10);467 468 dev_info(dev->dev, "Identified RDACM21 camera module\n");469 470 return 0;471}472 473static int rdacm21_initialize(struct rdacm21_device *dev)474{475 int ret;476 477 max9271_wake_up(&dev->serializer);478 479 /* Enable reverse channel and disable the serial link. */480 ret = max9271_set_serial_link(&dev->serializer, false);481 if (ret)482 return ret;483 484 /* Configure I2C bus at 105Kbps speed and configure GMSL. */485 ret = max9271_configure_i2c(&dev->serializer,486 MAX9271_I2CSLVSH_469NS_234NS |487 MAX9271_I2CSLVTO_1024US |488 MAX9271_I2CMSTBT_105KBPS);489 if (ret)490 return ret;491 492 ret = max9271_verify_id(&dev->serializer);493 if (ret)494 return ret;495 496 /*497 * Enable GPIO1 and hold OV490 in reset during max9271 configuration.498 * The reset signal has to be asserted for at least 250 useconds.499 */500 ret = max9271_enable_gpios(&dev->serializer, MAX9271_GPIO1OUT);501 if (ret)502 return ret;503 504 ret = max9271_clear_gpios(&dev->serializer, MAX9271_GPIO1OUT);505 if (ret)506 return ret;507 usleep_range(250, 500);508 509 ret = max9271_configure_gmsl_link(&dev->serializer);510 if (ret)511 return ret;512 513 ret = max9271_set_address(&dev->serializer, dev->addrs[0]);514 if (ret)515 return ret;516 dev->serializer.client->addr = dev->addrs[0];517 518 ret = max9271_set_translation(&dev->serializer, dev->addrs[1],519 OV490_I2C_ADDRESS);520 if (ret)521 return ret;522 dev->isp->addr = dev->addrs[1];523 524 /* Release OV490 from reset and initialize it. */525 ret = max9271_set_gpios(&dev->serializer, MAX9271_GPIO1OUT);526 if (ret)527 return ret;528 usleep_range(3000, 5000);529 530 ret = ov490_initialize(dev);531 if (ret)532 return ret;533 534 /*535 * Set reverse channel high threshold to increase noise immunity.536 *537 * This should be compensated by increasing the reverse channel538 * amplitude on the remote deserializer side.539 */540 return max9271_set_high_threshold(&dev->serializer, true);541}542 543static int rdacm21_probe(struct i2c_client *client)544{545 struct rdacm21_device *dev;546 int ret;547 548 dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL);549 if (!dev)550 return -ENOMEM;551 dev->dev = &client->dev;552 dev->serializer.client = client;553 554 ret = of_property_read_u32_array(client->dev.of_node, "reg",555 dev->addrs, 2);556 if (ret < 0) {557 dev_err(dev->dev, "Invalid DT reg property: %d\n", ret);558 return -EINVAL;559 }560 561 /* Create the dummy I2C client for the sensor. */562 dev->isp = i2c_new_dummy_device(client->adapter, OV490_I2C_ADDRESS);563 if (IS_ERR(dev->isp))564 return PTR_ERR(dev->isp);565 566 ret = rdacm21_initialize(dev);567 if (ret < 0)568 goto error;569 570 /* Initialize and register the subdevice. */571 v4l2_i2c_subdev_init(&dev->sd, client, &rdacm21_subdev_ops);572 dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;573 574 v4l2_ctrl_handler_init(&dev->ctrls, 1);575 v4l2_ctrl_new_std(&dev->ctrls, NULL, V4L2_CID_PIXEL_RATE,576 OV10640_PIXEL_RATE, OV10640_PIXEL_RATE, 1,577 OV10640_PIXEL_RATE);578 dev->sd.ctrl_handler = &dev->ctrls;579 580 ret = dev->ctrls.error;581 if (ret)582 goto error_free_ctrls;583 584 dev->pad.flags = MEDIA_PAD_FL_SOURCE;585 dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;586 ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad);587 if (ret < 0)588 goto error_free_ctrls;589 590 ret = v4l2_async_register_subdev(&dev->sd);591 if (ret)592 goto error_free_ctrls;593 594 return 0;595 596error_free_ctrls:597 v4l2_ctrl_handler_free(&dev->ctrls);598error:599 i2c_unregister_device(dev->isp);600 601 return ret;602}603 604static void rdacm21_remove(struct i2c_client *client)605{606 struct rdacm21_device *dev = sd_to_rdacm21(i2c_get_clientdata(client));607 608 v4l2_async_unregister_subdev(&dev->sd);609 v4l2_ctrl_handler_free(&dev->ctrls);610 i2c_unregister_device(dev->isp);611}612 613static const struct of_device_id rdacm21_of_ids[] = {614 { .compatible = "imi,rdacm21" },615 { }616};617MODULE_DEVICE_TABLE(of, rdacm21_of_ids);618 619static struct i2c_driver rdacm21_i2c_driver = {620 .driver = {621 .name = "rdacm21",622 .of_match_table = rdacm21_of_ids,623 },624 .probe = rdacm21_probe,625 .remove = rdacm21_remove,626};627 628module_i2c_driver(rdacm21_i2c_driver);629 630MODULE_DESCRIPTION("GMSL Camera driver for RDACM21");631MODULE_AUTHOR("Jacopo Mondi");632MODULE_LICENSE("GPL v2");633