1 From 9b1cd7fac64f53d070154fd6440ace60f6cfeab0 Mon Sep 17 00:00:00 2001
2 From: Markus Proeller <markus.proeller@pieye.org>
3 Date: Thu, 10 Oct 2019 19:12:36 +0200
4 Subject: [PATCH] media: i2c: Add a driver for the Infineon IRS1125
7 The Infineon IRS1125 is a time of flight depth sensor that
10 Add a V4L2 subdevice driver for this device.
12 Signed-off-by: Markus Proeller <markus.proeller@pieye.org>
14 drivers/media/i2c/Kconfig | 12 +
15 drivers/media/i2c/Makefile | 1 +
16 drivers/media/i2c/irs1125.c | 1112 +++++++++++++++++++++++++++++++++++
17 drivers/media/i2c/irs1125.h | 61 ++
18 4 files changed, 1186 insertions(+)
19 create mode 100644 drivers/media/i2c/irs1125.c
20 create mode 100644 drivers/media/i2c/irs1125.h
22 --- a/drivers/media/i2c/Kconfig
23 +++ b/drivers/media/i2c/Kconfig
24 @@ -1373,6 +1373,18 @@ config VIDEO_TW9910
25 To compile this driver as a module, choose M here: the
26 module will be called tw9910.
29 + tristate "Infineon IRS1125 sensor support"
30 + depends on I2C && VIDEO_DEV && VIDEO_V4L2_SUBDEV_API
31 + depends on MEDIA_CAMERA_SUPPORT
34 + This is a Video4Linux2 sensor-level driver for the Infineon
37 + To compile this driver as a module, choose M here: the
38 + module will be called irs1125.
41 tristate "vpx3220a, vpx3216b & vpx3214c video decoders"
42 depends on VIDEO_DEV && I2C
43 --- a/drivers/media/i2c/Makefile
44 +++ b/drivers/media/i2c/Makefile
45 @@ -51,6 +51,7 @@ obj-$(CONFIG_VIDEO_IMX412) += imx412.o
46 obj-$(CONFIG_VIDEO_IMX477) += imx477.o
47 obj-$(CONFIG_VIDEO_IMX519) += imx519.o
48 obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
49 +obj-$(CONFIG_VIDEO_IRS1125) += irs1125.o
50 obj-$(CONFIG_VIDEO_ISL7998X) += isl7998x.o
51 obj-$(CONFIG_VIDEO_KS0127) += ks0127.o
52 obj-$(CONFIG_VIDEO_LM3560) += lm3560.o
54 +++ b/drivers/media/i2c/irs1125.c
56 +// SPDX-License-Identifier: GPL-2.0
58 + * A V4L2 driver for Infineon IRS1125 TOF cameras.
59 + * Copyright (C) 2018, pieye GmbH
61 + * Based on V4L2 OmniVision OV5647 Image Sensor driver
62 + * Copyright (C) 2016 Ramiro Oliveira <roliveir@synopsys.com>
64 + * DT / fwnode changes, and GPIO control taken from ov5640.c
65 + * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
66 + * Copyright (C) 2014-2017 Mentor Graphics Inc.
71 +#include <linux/clk.h>
72 +#include <linux/delay.h>
73 +#include <linux/gpio/consumer.h>
74 +#include <linux/i2c.h>
75 +#include <linux/init.h>
76 +#include <linux/io.h>
77 +#include <linux/module.h>
78 +#include <linux/of_graph.h>
79 +#include <linux/slab.h>
80 +#include <linux/videodev2.h>
81 +#include <linux/firmware.h>
82 +#include <media/v4l2-device.h>
83 +#include <media/v4l2-fwnode.h>
84 +#include <media/v4l2-image-sizes.h>
85 +#include <media/v4l2-mediabus.h>
86 +#include <media/v4l2-ctrls.h>
88 +#define CHECK_BIT(val, pos) ((val) & BIT(pos))
90 +#define SENSOR_NAME "irs1125"
92 +#define RESET_ACTIVE_DELAY_MS 20
94 +#define IRS1125_ALTERNATE_FW "irs1125_af.bin"
96 +#define IRS1125_REG_CSICFG 0xA882
97 +#define IRS1125_REG_DESIGN_STEP 0xB0AD
98 +#define IRS1125_REG_EFUSEVAL2 0xB09F
99 +#define IRS1125_REG_EFUSEVAL3 0xB0A0
100 +#define IRS1125_REG_EFUSEVAL4 0xB0A1
101 +#define IRS1125_REG_DMEM_SHADOW 0xC320
103 +#define IRS1125_DESIGN_STEP_EXPECTED 0x0a12
105 +#define IRS1125_ROW_START_DEF 0
106 +#define IRS1125_COLUMN_START_DEF 0
107 +#define IRS1125_WINDOW_HEIGHT_DEF 288
108 +#define IRS1125_WINDOW_WIDTH_DEF 352
110 +struct regval_list {
116 + struct v4l2_subdev sd;
117 + struct media_pad pad;
118 + /* the parsed DT endpoint info */
119 + struct v4l2_fwnode_endpoint ep;
122 + struct v4l2_ctrl_handler ctrl_handler;
124 + /* To serialize asynchronus callbacks */
127 + /* image data layout */
128 + unsigned int num_seq;
131 + struct gpio_desc *reset;
133 + /* V4l2 Controls to grab */
134 + struct v4l2_ctrl *ctrl_modplls;
135 + struct v4l2_ctrl *ctrl_numseq;
140 +static inline struct irs1125 *to_state(struct v4l2_subdev *sd)
142 + return container_of(sd, struct irs1125, sd);
145 +static struct regval_list irs1125_26MHz[] = {
211 +static struct regval_list irs1125_seq_cfg[] = {
290 +static int irs1125_write(struct v4l2_subdev *sd, u16 reg, u16 val)
293 + unsigned char data[4] = { reg >> 8, reg & 0xff, val >> 8, val & 0xff};
294 + struct i2c_client *client = v4l2_get_subdevdata(sd);
296 + ret = i2c_master_send(client, data, 4);
298 + dev_err(&client->dev, "%s: i2c write error, reg: %x\n",
304 +static int irs1125_read(struct v4l2_subdev *sd, u16 reg, u16 *val)
307 + unsigned char data_w[2] = { reg >> 8, reg & 0xff };
310 + struct i2c_client *client = v4l2_get_subdevdata(sd);
312 + ret = i2c_master_send(client, data_w, 2);
314 + dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n",
319 + ret = i2c_master_recv(client, rdval, 2);
321 + dev_err(&client->dev, "%s: i2c read error, reg: %x\n",
324 + *val = rdval[1] | (rdval[0] << 8);
329 +static int irs1125_write_array(struct v4l2_subdev *sd,
330 + struct regval_list *regs, int array_size)
334 + for (i = 0; i < array_size; i++) {
335 + if (regs[i].addr == 0xFFFF) {
336 + msleep(regs[i].data);
338 + ret = irs1125_write(sd, regs[i].addr, regs[i].data);
347 +static int irs1125_stream_on(struct v4l2_subdev *sd)
350 + struct irs1125 *irs1125 = to_state(sd);
351 + struct i2c_client *client = v4l2_get_subdevdata(sd);
353 + v4l2_ctrl_grab(irs1125->ctrl_numseq, 1);
354 + v4l2_ctrl_grab(irs1125->ctrl_modplls, 1);
356 + ret = irs1125_write(sd, 0xC400, 0x0001);
358 + dev_err(&client->dev, "error enabling firmware: %d", ret);
364 + return irs1125_write(sd, 0xA87C, 0x0001);
367 +static int irs1125_stream_off(struct v4l2_subdev *sd)
370 + struct irs1125 *irs1125 = to_state(sd);
371 + struct i2c_client *client = v4l2_get_subdevdata(sd);
373 + v4l2_ctrl_grab(irs1125->ctrl_numseq, 0);
374 + v4l2_ctrl_grab(irs1125->ctrl_modplls, 0);
376 + ret = irs1125_write(sd, 0xA87C, 0x0000);
378 + dev_err(&client->dev, "error disabling trigger: %d", ret);
384 + return irs1125_write(sd, 0xC400, 0x0002);
387 +static int __sensor_init(struct v4l2_subdev *sd)
389 + unsigned int cnt, idx;
392 + struct i2c_client *client = v4l2_get_subdevdata(sd);
393 + struct irs1125 *irs1125 = to_state(sd);
394 + const struct firmware *fw;
395 + struct regval_list *reg_data;
399 + ret = irs1125_read(sd, 0xC40F, &val);
401 + dev_err(&client->dev, "read register 0xC40F failed\n");
404 + if (CHECK_BIT(val, 14) == 0)
408 + dev_err(&client->dev, "timeout waiting for 0xC40F\n");
415 + ret = irs1125_write_array(sd, irs1125_26MHz,
416 + ARRAY_SIZE(irs1125_26MHz));
418 + dev_err(&client->dev, "write sensor default regs error\n");
422 + /* set CSI-2 number of data lanes */
423 + if (irs1125->ep.bus.mipi_csi2.num_data_lanes == 1) {
425 + } else if (irs1125->ep.bus.mipi_csi2.num_data_lanes == 2) {
428 + dev_err(&client->dev, "invalid number of data lanes %d\n",
429 + irs1125->ep.bus.mipi_csi2.num_data_lanes);
433 + ret = irs1125_write(sd, IRS1125_REG_CSICFG, val);
435 + dev_err(&client->dev, "write sensor csi2 config error\n");
439 + /* request the firmware, this will block and timeout */
440 + ret = request_firmware(&fw, IRS1125_ALTERNATE_FW, &client->dev);
442 + dev_err(&client->dev,
443 + "did not find the firmware file '%s' (status %d)\n",
444 + IRS1125_ALTERNATE_FW, ret);
448 + if (fw->size % 4) {
449 + dev_err(&client->dev, "firmware file '%s' invalid\n",
450 + IRS1125_ALTERNATE_FW);
451 + release_firmware(fw);
455 + for (idx = 0; idx < fw->size; idx += 4) {
456 + reg_data = (struct regval_list *)&fw->data[idx];
457 + ret = irs1125_write(sd, reg_data->addr, reg_data->data);
459 + dev_err(&client->dev, "firmware write error\n");
460 + release_firmware(fw);
464 + release_firmware(fw);
466 + ret = irs1125_write_array(sd, irs1125_seq_cfg,
467 + ARRAY_SIZE(irs1125_seq_cfg));
469 + dev_err(&client->dev, "write default sequence failed\n");
476 +static int irs1125_sensor_power(struct v4l2_subdev *sd, int on)
479 + struct irs1125 *irs1125 = to_state(sd);
480 + struct i2c_client *client = v4l2_get_subdevdata(sd);
482 + mutex_lock(&irs1125->lock);
484 + if (on && !irs1125->power_count) {
485 + gpiod_set_value_cansleep(irs1125->reset, 1);
486 + msleep(RESET_ACTIVE_DELAY_MS);
488 + ret = clk_prepare_enable(irs1125->xclk);
490 + dev_err(&client->dev, "clk prepare enable failed\n");
494 + ret = __sensor_init(sd);
496 + clk_disable_unprepare(irs1125->xclk);
497 + dev_err(&client->dev,
498 + "Camera not available, check Power\n");
501 + } else if (!on && irs1125->power_count == 1) {
502 + gpiod_set_value_cansleep(irs1125->reset, 0);
505 + /* Update the power count. */
506 + irs1125->power_count += on ? 1 : -1;
507 + WARN_ON(irs1125->power_count < 0);
510 + mutex_unlock(&irs1125->lock);
515 +#ifdef CONFIG_VIDEO_ADV_DEBUG
516 +static int irs1125_sensor_get_register(struct v4l2_subdev *sd,
517 + struct v4l2_dbg_register *reg)
522 + ret = irs1125_read(sd, reg->reg & 0xffff, &val);
532 +static int irs1125_sensor_set_register(struct v4l2_subdev *sd,
533 + const struct v4l2_dbg_register *reg)
535 + return irs1125_write(sd, reg->reg & 0xffff, reg->val & 0xffff);
539 +static const struct v4l2_subdev_core_ops irs1125_subdev_core_ops = {
540 + .s_power = irs1125_sensor_power,
541 +#ifdef CONFIG_VIDEO_ADV_DEBUG
542 + .g_register = irs1125_sensor_get_register,
543 + .s_register = irs1125_sensor_set_register,
547 +static int irs1125_s_stream(struct v4l2_subdev *sd, int enable)
550 + return irs1125_stream_on(sd);
552 + return irs1125_stream_off(sd);
555 +static const struct v4l2_subdev_video_ops irs1125_subdev_video_ops = {
556 + .s_stream = irs1125_s_stream,
559 +static int irs1125_enum_mbus_code(struct v4l2_subdev *sd,
560 + struct v4l2_subdev_pad_config *cfg,
561 + struct v4l2_subdev_mbus_code_enum *code)
563 + if (code->index > 0)
566 + code->code = MEDIA_BUS_FMT_Y12_1X12;
571 +static int irs1125_set_get_fmt(struct v4l2_subdev *sd,
572 + struct v4l2_subdev_pad_config *cfg,
573 + struct v4l2_subdev_format *format)
575 + struct v4l2_mbus_framefmt *fmt = &format->format;
576 + struct irs1125 *irs1125 = to_state(sd);
578 + if (format->pad != 0)
581 + /* Only one format is supported, so return that */
582 + memset(fmt, 0, sizeof(*fmt));
583 + fmt->code = MEDIA_BUS_FMT_Y12_1X12;
584 + fmt->colorspace = V4L2_COLORSPACE_RAW;
585 + fmt->field = V4L2_FIELD_NONE;
586 + fmt->width = IRS1125_WINDOW_WIDTH_DEF;
587 + fmt->height = IRS1125_WINDOW_HEIGHT_DEF * irs1125->num_seq;
592 +static const struct v4l2_subdev_pad_ops irs1125_subdev_pad_ops = {
593 + .enum_mbus_code = irs1125_enum_mbus_code,
594 + .set_fmt = irs1125_set_get_fmt,
595 + .get_fmt = irs1125_set_get_fmt,
598 +static const struct v4l2_subdev_ops irs1125_subdev_ops = {
599 + .core = &irs1125_subdev_core_ops,
600 + .video = &irs1125_subdev_video_ops,
601 + .pad = &irs1125_subdev_pad_ops,
604 +static int irs1125_s_ctrl(struct v4l2_ctrl *ctrl)
606 + struct irs1125 *dev = container_of(ctrl->handler,
607 + struct irs1125, ctrl_handler);
608 + struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
610 + struct irs1125_mod_pll *mod_cur, *mod_new;
611 + struct irs1125_seq_cfg *cfg_cur, *cfg_new;
616 + switch (ctrl->id) {
617 + case IRS1125_CID_SAFE_RECONFIG:
619 + struct irs1125_illu *illu_cur, *illu_new;
621 + illu_new = (struct irs1125_illu *)ctrl->p_new.p;
622 + illu_cur = (struct irs1125_illu *)ctrl->p_cur.p;
623 + for (i = 0; i < IRS1125_NUM_SEQ_ENTRIES; i++) {
624 + if (illu_cur[i].exposure != illu_new[i].exposure) {
625 + addr = 0xA850 + i * 2;
626 + val = illu_new[i].exposure;
627 + err = irs1125_write(&dev->sd, addr, val);
631 + if (illu_cur[i].framerate != illu_new[i].framerate) {
632 + addr = 0xA851 + i * 2;
633 + val = illu_new[i].framerate;
634 + err = irs1125_write(&dev->sd, addr, val);
641 + case IRS1125_CID_MOD_PLL:
642 + mod_new = (struct irs1125_mod_pll *)ctrl->p_new.p;
643 + mod_cur = (struct irs1125_mod_pll *)ctrl->p_cur.p;
644 + for (i = 0; i < IRS1125_NUM_MOD_PLLS; i++) {
645 + if (mod_cur[i].pllcfg1 != mod_new[i].pllcfg1) {
646 + addr = 0xC3A0 + i * 3;
647 + val = mod_new[i].pllcfg1;
648 + err = irs1125_write(&dev->sd, addr, val);
652 + if (mod_cur[i].pllcfg2 != mod_new[i].pllcfg2) {
653 + addr = 0xC3A1 + i * 3;
654 + val = mod_new[i].pllcfg2;
655 + err = irs1125_write(&dev->sd, addr, val);
659 + if (mod_cur[i].pllcfg3 != mod_new[i].pllcfg3) {
660 + addr = 0xC3A2 + i * 3;
661 + val = mod_new[i].pllcfg3;
662 + err = irs1125_write(&dev->sd, addr, val);
666 + if (mod_cur[i].pllcfg4 != mod_new[i].pllcfg4) {
667 + addr = 0xC24C + i * 5;
668 + val = mod_new[i].pllcfg4;
669 + err = irs1125_write(&dev->sd, addr, val);
673 + if (mod_cur[i].pllcfg5 != mod_new[i].pllcfg5) {
674 + addr = 0xC24D + i * 5;
675 + val = mod_new[i].pllcfg5;
676 + err = irs1125_write(&dev->sd, addr, val);
680 + if (mod_cur[i].pllcfg6 != mod_new[i].pllcfg6) {
681 + addr = 0xC24E + i * 5;
682 + val = mod_new[i].pllcfg6;
683 + err = irs1125_write(&dev->sd, addr, val);
687 + if (mod_cur[i].pllcfg7 != mod_new[i].pllcfg7) {
688 + addr = 0xC24F + i * 5;
689 + val = mod_new[i].pllcfg7;
690 + err = irs1125_write(&dev->sd, addr, val);
694 + if (mod_cur[i].pllcfg8 != mod_new[i].pllcfg8) {
695 + addr = 0xC250 + i * 5;
696 + val = mod_new[i].pllcfg8;
697 + err = irs1125_write(&dev->sd, addr, val);
703 + case IRS1125_CID_SEQ_CONFIG:
704 + cfg_new = (struct irs1125_seq_cfg *)ctrl->p_new.p;
705 + cfg_cur = (struct irs1125_seq_cfg *)ctrl->p_cur.p;
706 + for (i = 0; i < IRS1125_NUM_SEQ_ENTRIES; i++) {
707 + if (cfg_cur[i].exposure != cfg_new[i].exposure) {
708 + addr = IRS1125_REG_DMEM_SHADOW + i * 4;
709 + val = cfg_new[i].exposure;
710 + err = irs1125_write(&dev->sd, addr, val);
714 + if (cfg_cur[i].framerate != cfg_new[i].framerate) {
715 + addr = IRS1125_REG_DMEM_SHADOW + 1 + i * 4;
716 + val = cfg_new[i].framerate;
717 + err = irs1125_write(&dev->sd, addr, val);
721 + if (cfg_cur[i].ps != cfg_new[i].ps) {
722 + addr = IRS1125_REG_DMEM_SHADOW + 2 + i * 4;
723 + val = cfg_new[i].ps;
724 + err = irs1125_write(&dev->sd, addr, val);
728 + if (cfg_cur[i].pll != cfg_new[i].pll) {
729 + addr = IRS1125_REG_DMEM_SHADOW + 3 + i * 4;
730 + val = cfg_new[i].pll;
731 + err = irs1125_write(&dev->sd, addr, val);
737 + case IRS1125_CID_NUM_SEQS:
738 + err = irs1125_write(&dev->sd, 0xA88D, ctrl->val - 1);
740 + dev->num_seq = ctrl->val;
742 + case IRS1125_CID_CONTINUOUS_TRIG:
743 + if (ctrl->val == 0)
744 + err = irs1125_write(&dev->sd, 0xA87C, 0);
746 + err = irs1125_write(&dev->sd, 0xA87C, 1);
748 + case IRS1125_CID_TRIGGER:
749 + if (ctrl->val != 0) {
750 + err = irs1125_write(&dev->sd, 0xA87C, 1);
752 + err = irs1125_write(&dev->sd, 0xA87C, 0);
755 + case IRS1125_CID_RECONFIG:
756 + if (ctrl->val != 0)
757 + err = irs1125_write(&dev->sd, 0xA87A, 1);
759 + case IRS1125_CID_ILLU_ON:
760 + if (ctrl->val == 0)
761 + err = irs1125_write(&dev->sd, 0xA892, 0x377);
763 + err = irs1125_write(&dev->sd, 0xA892, 0x355);
770 + dev_err(&client->dev, "Error executing control ID: %d, val %d, err %d",
771 + ctrl->id, ctrl->val, err);
778 +static const struct v4l2_ctrl_ops irs1125_ctrl_ops = {
779 + .s_ctrl = irs1125_s_ctrl,
782 +static const struct v4l2_ctrl_config irs1125_custom_ctrls[] = {
784 + .ops = &irs1125_ctrl_ops,
785 + .id = IRS1125_CID_NUM_SEQS,
786 + .name = "Change number of sequences",
787 + .type = V4L2_CTRL_TYPE_INTEGER,
788 + .flags = V4L2_CTRL_FLAG_MODIFY_LAYOUT,
794 + .ops = &irs1125_ctrl_ops,
795 + .id = IRS1125_CID_MOD_PLL,
796 + .name = "Reconfigure modulation PLLs",
797 + .type = V4L2_CTRL_TYPE_U16,
798 + .flags = V4L2_CTRL_FLAG_HAS_PAYLOAD,
803 + .elem_size = sizeof(u16),
804 + .dims = {sizeof(struct irs1125_mod_pll) / sizeof(u16),
805 + IRS1125_NUM_MOD_PLLS}
807 + .ops = &irs1125_ctrl_ops,
808 + .id = IRS1125_CID_SAFE_RECONFIG,
809 + .name = "Change exposure and pause of single seq",
810 + .type = V4L2_CTRL_TYPE_U16,
811 + .flags = V4L2_CTRL_FLAG_HAS_PAYLOAD,
816 + .elem_size = sizeof(u16),
817 + .dims = {sizeof(struct irs1125_illu) / sizeof(u16),
818 + IRS1125_NUM_SEQ_ENTRIES}
820 + .ops = &irs1125_ctrl_ops,
821 + .id = IRS1125_CID_SEQ_CONFIG,
822 + .name = "Change sequence settings",
823 + .type = V4L2_CTRL_TYPE_U16,
824 + .flags = V4L2_CTRL_FLAG_HAS_PAYLOAD,
829 + .elem_size = sizeof(u16),
830 + .dims = {sizeof(struct irs1125_seq_cfg) / sizeof(u16),
831 + IRS1125_NUM_SEQ_ENTRIES}
833 + .ops = &irs1125_ctrl_ops,
834 + .id = IRS1125_CID_CONTINUOUS_TRIG,
835 + .name = "Enable/disable continuous trigger",
836 + .type = V4L2_CTRL_TYPE_BOOLEAN,
837 + .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE,
843 + .ops = &irs1125_ctrl_ops,
844 + .id = IRS1125_CID_TRIGGER,
845 + .name = "Capture a single sequence",
846 + .type = V4L2_CTRL_TYPE_BOOLEAN,
847 + .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE,
853 + .ops = &irs1125_ctrl_ops,
854 + .id = IRS1125_CID_RECONFIG,
855 + .name = "Trigger imager reconfiguration",
856 + .type = V4L2_CTRL_TYPE_BOOLEAN,
857 + .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE,
863 + .ops = &irs1125_ctrl_ops,
864 + .id = IRS1125_CID_ILLU_ON,
865 + .name = "Turn illu on or off",
866 + .type = V4L2_CTRL_TYPE_BOOLEAN,
867 + .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE,
873 + .ops = &irs1125_ctrl_ops,
874 + .id = IRS1125_CID_IDENT0,
875 + .name = "Get ident 0 information",
876 + .type = V4L2_CTRL_TYPE_INTEGER,
877 + .flags = V4L2_CTRL_FLAG_READ_ONLY,
883 + .ops = &irs1125_ctrl_ops,
884 + .id = IRS1125_CID_IDENT1,
885 + .name = "Get ident 1 information",
886 + .type = V4L2_CTRL_TYPE_INTEGER,
887 + .flags = V4L2_CTRL_FLAG_READ_ONLY,
893 + .ops = &irs1125_ctrl_ops,
894 + .id = IRS1125_CID_IDENT2,
895 + .name = "Get ident 2 information",
896 + .type = V4L2_CTRL_TYPE_INTEGER,
897 + .flags = V4L2_CTRL_FLAG_READ_ONLY,
905 +static int irs1125_detect(struct v4l2_subdev *sd)
909 + struct i2c_client *client = v4l2_get_subdevdata(sd);
911 + ret = irs1125_read(sd, IRS1125_REG_DESIGN_STEP, &read);
913 + dev_err(&client->dev, "error reading from i2c\n");
917 + if (read != IRS1125_DESIGN_STEP_EXPECTED) {
918 + dev_err(&client->dev, "Design step expected 0x%x got 0x%x",
919 + IRS1125_DESIGN_STEP_EXPECTED, read);
926 +static int irs1125_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
928 + struct v4l2_mbus_framefmt *format =
929 + v4l2_subdev_get_try_format(sd, fh->pad, 0);
931 + format->code = MEDIA_BUS_FMT_Y12_1X12;
932 + format->width = IRS1125_WINDOW_WIDTH_DEF;
933 + format->height = IRS1125_WINDOW_HEIGHT_DEF;
934 + format->field = V4L2_FIELD_NONE;
935 + format->colorspace = V4L2_COLORSPACE_RAW;
940 +static const struct v4l2_subdev_internal_ops irs1125_subdev_internal_ops = {
941 + .open = irs1125_open,
944 +static int irs1125_ctrls_init(struct irs1125 *sensor, struct device *dev)
946 + struct v4l2_ctrl *ctrl;
948 + struct v4l2_ctrl_handler *hdl;
950 + hdl = &sensor->ctrl_handler;
951 + v4l2_ctrl_handler_init(hdl, ARRAY_SIZE(irs1125_custom_ctrls));
953 + for (i = 0; i < ARRAY_SIZE(irs1125_custom_ctrls); i++) {
954 + ctrl = v4l2_ctrl_new_custom(hdl, &irs1125_custom_ctrls[i],
957 + dev_err(dev, "Failed to init custom control %s\n",
958 + irs1125_custom_ctrls[i].name);
959 + else if (irs1125_custom_ctrls[i].id == IRS1125_CID_NUM_SEQS)
960 + sensor->ctrl_numseq = ctrl;
961 + else if (irs1125_custom_ctrls[i].id == IRS1125_CID_MOD_PLL)
962 + sensor->ctrl_modplls = ctrl;
966 + dev_err(dev, "Error %d adding controls\n", hdl->error);
971 + sensor->sd.ctrl_handler = hdl;
975 + v4l2_ctrl_handler_free(&sensor->ctrl_handler);
979 +static int irs1125_ident_setup(struct irs1125 *sensor, struct device *dev)
982 + struct v4l2_ctrl *ctrl;
983 + struct v4l2_subdev *sd;
988 + ctrl = v4l2_ctrl_find(&sensor->ctrl_handler, IRS1125_CID_IDENT0);
990 + dev_err(dev, "could not find device ctrl.\n");
994 + ret = irs1125_read(sd, IRS1125_REG_EFUSEVAL2, &read);
996 + dev_err(dev, "error reading from i2c\n");
1000 + v4l2_ctrl_s_ctrl(ctrl, read);
1002 + ctrl = v4l2_ctrl_find(&sensor->ctrl_handler, IRS1125_CID_IDENT1);
1004 + dev_err(dev, "could not find device ctrl.\n");
1008 + ret = irs1125_read(sd, IRS1125_REG_EFUSEVAL3, &read);
1010 + dev_err(dev, "error reading from i2c\n");
1014 + v4l2_ctrl_s_ctrl(ctrl, read);
1016 + ctrl = v4l2_ctrl_find(&sensor->ctrl_handler, IRS1125_CID_IDENT2);
1018 + dev_err(dev, "could not find device ctrl.\n");
1022 + ret = irs1125_read(sd, IRS1125_REG_EFUSEVAL4, &read);
1024 + dev_err(dev, "error reading from i2c\n");
1027 + v4l2_ctrl_s_ctrl(ctrl, read & 0xFFFC);
1032 +static int irs1125_probe(struct i2c_client *client,
1033 + const struct i2c_device_id *id)
1035 + struct device *dev = &client->dev;
1036 + struct irs1125 *sensor;
1038 + struct fwnode_handle *endpoint;
1042 + sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
1046 + v4l2_i2c_subdev_init(&sensor->sd, client, &irs1125_subdev_ops);
1048 + /* Get CSI2 bus config */
1049 + endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev),
1052 + dev_err(dev, "endpoint node not found\n");
1056 + ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep);
1057 + fwnode_handle_put(endpoint);
1059 + dev_err(dev, "Could not parse endpoint\n");
1063 + /* get system clock (xclk) */
1064 + sensor->xclk = devm_clk_get(dev, NULL);
1065 + if (IS_ERR(sensor->xclk)) {
1066 + dev_err(dev, "could not get xclk");
1067 + return PTR_ERR(sensor->xclk);
1070 + xclk_freq = clk_get_rate(sensor->xclk);
1071 + if (xclk_freq != 26000000) {
1072 + dev_err(dev, "Unsupported clock frequency: %u\n", xclk_freq);
1076 + sensor->num_seq = 5;
1078 + /* Request the power down GPIO */
1079 + sensor->reset = devm_gpiod_get(&client->dev, "pwdn",
1082 + if (IS_ERR(sensor->reset)) {
1083 + dev_err(dev, "could not get reset");
1084 + return PTR_ERR(sensor->reset);
1087 + gpio_num = desc_to_gpio(sensor->reset);
1089 + mutex_init(&sensor->lock);
1091 + ret = irs1125_ctrls_init(sensor, dev);
1093 + goto mutex_remove;
1095 + sensor->sd.internal_ops = &irs1125_subdev_internal_ops;
1096 + sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1097 + sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
1098 + sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
1099 + ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
1101 + goto mutex_remove;
1103 + gpiod_set_value_cansleep(sensor->reset, 1);
1104 + msleep(RESET_ACTIVE_DELAY_MS);
1106 + ret = irs1125_detect(&sensor->sd);
1110 + ret = irs1125_ident_setup(sensor, dev);
1114 + gpiod_set_value_cansleep(sensor->reset, 0);
1116 + ret = v4l2_async_register_subdev(&sensor->sd);
1120 + dev_dbg(dev, "Infineon IRS1125 camera driver probed\n");
1125 + media_entity_cleanup(&sensor->sd.entity);
1127 + mutex_destroy(&sensor->lock);
1131 +static int irs1125_remove(struct i2c_client *client)
1133 + struct v4l2_subdev *sd = i2c_get_clientdata(client);
1134 + struct irs1125 *irs1125 = to_state(sd);
1136 + v4l2_async_unregister_subdev(&irs1125->sd);
1137 + media_entity_cleanup(&irs1125->sd.entity);
1138 + v4l2_device_unregister_subdev(sd);
1139 + mutex_destroy(&irs1125->lock);
1140 + v4l2_ctrl_handler_free(&irs1125->ctrl_handler);
1145 +#if IS_ENABLED(CONFIG_OF)
1146 +static const struct of_device_id irs1125_of_match[] = {
1147 + { .compatible = "infineon,irs1125" },
1148 + { /* sentinel */ },
1150 +MODULE_DEVICE_TABLE(of, irs1125_of_match);
1153 +static struct i2c_driver irs1125_driver = {
1155 + .of_match_table = of_match_ptr(irs1125_of_match),
1156 + .name = SENSOR_NAME,
1158 + .probe = irs1125_probe,
1159 + .remove = irs1125_remove,
1162 +module_i2c_driver(irs1125_driver);
1164 +MODULE_AUTHOR("Markus Proeller <markus.proeller@pieye.org>");
1165 +MODULE_DESCRIPTION("Infineon irs1125 sensor driver");
1166 +MODULE_LICENSE("GPL v2");
1169 +++ b/drivers/media/i2c/irs1125.h
1171 +/* SPDX-License-Identifier: GPL-2.0 */
1173 + * A V4L2 driver for Infineon IRS1125 TOF cameras.
1174 + * Copyright (C) 2018, pieye GmbH
1176 + * Based on V4L2 OmniVision OV5647 Image Sensor driver
1177 + * Copyright (C) 2016 Ramiro Oliveira <roliveir@synopsys.com>
1179 + * DT / fwnode changes, and GPIO control taken from ov5640.c
1180 + * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
1181 + * Copyright (C) 2014-2017 Mentor Graphics Inc.
1188 +#include <linux/v4l2-controls.h>
1189 +#include <linux/types.h>
1191 +#define IRS1125_NUM_SEQ_ENTRIES 20
1192 +#define IRS1125_NUM_MOD_PLLS 4
1194 +#define IRS1125_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000)
1195 +#define IRS1125_CID_SAFE_RECONFIG (IRS1125_CID_CUSTOM_BASE + 0)
1196 +#define IRS1125_CID_CONTINUOUS_TRIG (IRS1125_CID_CUSTOM_BASE + 1)
1197 +#define IRS1125_CID_TRIGGER (IRS1125_CID_CUSTOM_BASE + 2)
1198 +#define IRS1125_CID_RECONFIG (IRS1125_CID_CUSTOM_BASE + 3)
1199 +#define IRS1125_CID_ILLU_ON (IRS1125_CID_CUSTOM_BASE + 4)
1200 +#define IRS1125_CID_NUM_SEQS (IRS1125_CID_CUSTOM_BASE + 5)
1201 +#define IRS1125_CID_MOD_PLL (IRS1125_CID_CUSTOM_BASE + 6)
1202 +#define IRS1125_CID_SEQ_CONFIG (IRS1125_CID_CUSTOM_BASE + 7)
1203 +#define IRS1125_CID_IDENT0 (IRS1125_CID_CUSTOM_BASE + 8)
1204 +#define IRS1125_CID_IDENT1 (IRS1125_CID_CUSTOM_BASE + 9)
1205 +#define IRS1125_CID_IDENT2 (IRS1125_CID_CUSTOM_BASE + 10)
1207 +struct irs1125_seq_cfg {
1214 +struct irs1125_illu {
1219 +struct irs1125_mod_pll {
1230 +#endif /* IRS1125 */