linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/5] Add the cat24c208 EDID EEPROM driver + new EDID capability
@ 2022-09-28 11:21 Erling Ljunggren
  2022-09-28 11:21 ` [PATCH v3 1/5] media: videodev2.h: add V4L2_CAP_EDID Erling Ljunggren
                   ` (4 more replies)
  0 siblings, 5 replies; 9+ messages in thread
From: Erling Ljunggren @ 2022-09-28 11:21 UTC (permalink / raw)
  To: linux-media; +Cc: Erling Ljunggren

This series adds support for the standalone cat24c208 EDID EEPROM i2c device.
Usually EDID support is part of an HDMI receiver, but this is a standalone EEPROM.

Note that EEPROMs for EDIDs are not regular EEPROM devices, these are dual port
devices that follow the VESA E-DDC standard.

Since this is a standalone device that does not capture any video a new
V4L2_CAP_EDID capability is introduced to represent such devices.
Note that such a device doesn't have to be an EEPROM, it can also be
implemented using a microcontroller, for example.

v3:
 - use old V4L2_CAP_ASYNCIO (0x02000000) capability bit
 - validate physical address of edid in driver
 - handle empty edid in driver
 - add cec notifier support to driver
 - update driver and bindings with hpd gpio support
 - removed references to "memory" in capability and docs
 - associate ioctls based on device direction

v2:
 - fix dt binding example
 - rename i2c client variables in data struct
 - fix include: of_device.h -> mod_devicetable.h
 - Sorted makefile
 - used define EDID_OFFSET_EXT_FLAG instead of magic number
 - removed of_match_ptr
 - added bus_info
 - remove unneeded headers
 - add depends on OF to Kconfig


Erling Ljunggren (4):
  media: videodev2.h: add V4L2_CAP_EDID
  media: docs: Add V4L2_CAP_EDID
  dt-bindings: media: add cat24c208 bindings
  media: v4l2-dev: handle V4L2_CAP_EDID

Jonathan Selnes (1):
  media: i2c: cat24c208: driver for the cat24c208 EDID EEPROM

 .../bindings/media/i2c/onnn,cat24c208.yaml    |  48 ++
 .../userspace-api/media/v4l/biblio.rst        |  11 +
 .../media/v4l/vidioc-querycap.rst             |  11 +
 .../media/videodev2.h.rst.exceptions          |   1 +
 MAINTAINERS                                   |   7 +
 drivers/media/i2c/Kconfig                     |   9 +
 drivers/media/i2c/Makefile                    |   1 +
 drivers/media/i2c/cat24c208.c                 | 480 ++++++++++++++++++
 drivers/media/v4l2-core/v4l2-dev.c            |  15 +
 include/uapi/linux/videodev2.h                |   1 +
 10 files changed, 584 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/i2c/onnn,cat24c208.yaml
 create mode 100644 drivers/media/i2c/cat24c208.c

-- 
2.37.3


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v3 1/5] media: videodev2.h: add V4L2_CAP_EDID
  2022-09-28 11:21 [PATCH v3 0/5] Add the cat24c208 EDID EEPROM driver + new EDID capability Erling Ljunggren
@ 2022-09-28 11:21 ` Erling Ljunggren
  2022-09-28 11:21 ` [PATCH v3 2/5] media: docs: Add V4L2_CAP_EDID Erling Ljunggren
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Erling Ljunggren @ 2022-09-28 11:21 UTC (permalink / raw)
  To: linux-media; +Cc: Erling Ljunggren

Add capability flag to indicate that the device is an EDID-only device.

Signed-off-by: Erling Ljunggren <hljunggr@cisco.com>
---
 include/uapi/linux/videodev2.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 054fc8bbdb22..2ea95639f441 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -480,6 +480,7 @@ struct v4l2_capability {
 #define V4L2_CAP_META_CAPTURE		0x00800000  /* Is a metadata capture device */
 
 #define V4L2_CAP_READWRITE              0x01000000  /* read/write systemcalls */
+#define V4L2_CAP_EDID			0x02000000  /* Is an EDID-only device */
 #define V4L2_CAP_STREAMING              0x04000000  /* streaming I/O ioctls */
 #define V4L2_CAP_META_OUTPUT		0x08000000  /* Is a metadata output device */
 
-- 
2.37.3


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 2/5] media: docs: Add V4L2_CAP_EDID
  2022-09-28 11:21 [PATCH v3 0/5] Add the cat24c208 EDID EEPROM driver + new EDID capability Erling Ljunggren
  2022-09-28 11:21 ` [PATCH v3 1/5] media: videodev2.h: add V4L2_CAP_EDID Erling Ljunggren
@ 2022-09-28 11:21 ` Erling Ljunggren
  2022-09-28 11:21 ` [PATCH v3 3/5] dt-bindings: media: add cat24c208 bindings Erling Ljunggren
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Erling Ljunggren @ 2022-09-28 11:21 UTC (permalink / raw)
  To: linux-media; +Cc: Erling Ljunggren

Add documentation for the new edid capability.

Signed-off-by: Erling Ljunggren <hljunggr@cisco.com>
---
 Documentation/userspace-api/media/v4l/biblio.rst      | 11 +++++++++++
 .../userspace-api/media/v4l/vidioc-querycap.rst       | 11 +++++++++++
 .../userspace-api/media/videodev2.h.rst.exceptions    |  1 +
 3 files changed, 23 insertions(+)

diff --git a/Documentation/userspace-api/media/v4l/biblio.rst b/Documentation/userspace-api/media/v4l/biblio.rst
index 9cd18c153d19..5cbe41877a63 100644
--- a/Documentation/userspace-api/media/v4l/biblio.rst
+++ b/Documentation/userspace-api/media/v4l/biblio.rst
@@ -334,6 +334,17 @@ VESA DMT
 
 :author:    Video Electronics Standards Association (http://www.vesa.org)
 
+.. _vesaeddc:
+
+E-DDC
+====
+
+
+:title:     VESA Enhanced Display Data Channel (E-DDC) Standard
+:subtitle:  Version 1.3
+
+:author:    Video Electronics Standards Association (http://www.vesa.org)
+
 .. _vesaedid:
 
 EDID
diff --git a/Documentation/userspace-api/media/v4l/vidioc-querycap.rst b/Documentation/userspace-api/media/v4l/vidioc-querycap.rst
index 6c57b8428356..3d11d86d9cbf 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-querycap.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-querycap.rst
@@ -244,6 +244,17 @@ specification the ioctl returns an ``EINVAL`` error code.
       - 0x01000000
       - The device supports the :c:func:`read()` and/or
 	:c:func:`write()` I/O methods.
+    * - ``V4L2_CAP_EDID``
+      - 0x02000000
+      - The device stores the EDID for a video input, or retrieves the EDID for a video
+        output. It is a standalone EDID device, so no video streaming etc. will take place.
+
+        For a video input this is typically an eeprom that supports the
+        :ref:`VESA Enhanced Display Data Channel Standard <vesaeddc>`. It can be something
+        else as well, for example a micro controller.
+
+        For a video output this is typically read from an external device such as an
+        HDMI splitter accessed by a serial port.
     * - ``V4L2_CAP_STREAMING``
       - 0x04000000
       - The device supports the :ref:`streaming <mmap>` I/O method.
diff --git a/Documentation/userspace-api/media/videodev2.h.rst.exceptions b/Documentation/userspace-api/media/videodev2.h.rst.exceptions
index 9cbb7a0c354a..b1b1127d278c 100644
--- a/Documentation/userspace-api/media/videodev2.h.rst.exceptions
+++ b/Documentation/userspace-api/media/videodev2.h.rst.exceptions
@@ -185,6 +185,7 @@ replace define V4L2_CAP_META_OUTPUT device-capabilities
 replace define V4L2_CAP_DEVICE_CAPS device-capabilities
 replace define V4L2_CAP_TOUCH device-capabilities
 replace define V4L2_CAP_IO_MC device-capabilities
+replace define V4L2_CAP_EDID device-capabilities
 
 # V4L2 pix flags
 replace define V4L2_PIX_FMT_PRIV_MAGIC :c:type:`v4l2_pix_format`
-- 
2.37.3


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 3/5] dt-bindings: media: add cat24c208 bindings
  2022-09-28 11:21 [PATCH v3 0/5] Add the cat24c208 EDID EEPROM driver + new EDID capability Erling Ljunggren
  2022-09-28 11:21 ` [PATCH v3 1/5] media: videodev2.h: add V4L2_CAP_EDID Erling Ljunggren
  2022-09-28 11:21 ` [PATCH v3 2/5] media: docs: Add V4L2_CAP_EDID Erling Ljunggren
@ 2022-09-28 11:21 ` Erling Ljunggren
  2022-09-28 22:37   ` Rob Herring
  2022-09-29 13:26   ` Rob Herring
  2022-09-28 11:21 ` [PATCH v3 4/5] media: i2c: cat24c208: driver for the cat24c208 EDID EEPROM Erling Ljunggren
  2022-09-28 11:21 ` [PATCH v3 5/5] media: v4l2-dev: handle V4L2_CAP_EDID Erling Ljunggren
  4 siblings, 2 replies; 9+ messages in thread
From: Erling Ljunggren @ 2022-09-28 11:21 UTC (permalink / raw)
  To: linux-media; +Cc: Erling Ljunggren, devicetree

Add devicetree bindings for new cat24c208 EDID EEPROM driver.

Signed-off-by: Erling Ljunggren <hljunggr@cisco.com>
---
 .../bindings/media/i2c/onnn,cat24c208.yaml    | 48 +++++++++++++++++++
 1 file changed, 48 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/i2c/onnn,cat24c208.yaml

diff --git a/Documentation/devicetree/bindings/media/i2c/onnn,cat24c208.yaml b/Documentation/devicetree/bindings/media/i2c/onnn,cat24c208.yaml
new file mode 100644
index 000000000000..fcfaccb5e39f
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/onnn,cat24c208.yaml
@@ -0,0 +1,48 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/onnn,cat24c208.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ON Semiconductor CAT24C208 EDID EEPROM driver
+
+maintainers:
+  - Hans Verkuil <hverkuil-cisco@xs4all.nl>
+
+description: |
+  CAT24C208 is a dual port i2c EEPROM designed for EDID storage.
+
+
+properties:
+  compatible:
+    const: onnn,cat24c208
+
+  reg:
+    maxItems: 1
+
+  hpd-gpios:
+    maxItems: 1
+    description:
+      References to the GPIO that controls the HDMI hot-plug detection pin.
+      The active flag indicates the GPIO level that enables hot-plug detection.
+
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        cat24c208@31 {
+            compatible = "onnn,cat24c208";
+            reg = <0x31>;
+            hpd-gpios = <&ioexp 0 GPIO_ACTIVE_HIGH>;
+        };
+    };
+...
-- 
2.37.3


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 4/5] media: i2c: cat24c208: driver for the cat24c208 EDID EEPROM
  2022-09-28 11:21 [PATCH v3 0/5] Add the cat24c208 EDID EEPROM driver + new EDID capability Erling Ljunggren
                   ` (2 preceding siblings ...)
  2022-09-28 11:21 ` [PATCH v3 3/5] dt-bindings: media: add cat24c208 bindings Erling Ljunggren
@ 2022-09-28 11:21 ` Erling Ljunggren
  2022-09-28 11:21 ` [PATCH v3 5/5] media: v4l2-dev: handle V4L2_CAP_EDID Erling Ljunggren
  4 siblings, 0 replies; 9+ messages in thread
From: Erling Ljunggren @ 2022-09-28 11:21 UTC (permalink / raw)
  To: linux-media; +Cc: Jonathan Selnes, Hans Verkuil, Erling Ljunggren

From: Jonathan Selnes <jonathansb1@gmail.com>

Support reading and writing the EDID EEPROM through the
v4l2 API.

Signed-off-by: Jonathan Selnes <jonathansb1@gmail.com>
Co-developed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Co-developed-by: Erling Ljunggren <hljunggr@cisco.com>
Signed-off-by: Erling Ljunggren <hljunggr@cisco.com>
---
 MAINTAINERS                   |   7 +
 drivers/media/i2c/Kconfig     |   9 +
 drivers/media/i2c/Makefile    |   1 +
 drivers/media/i2c/cat24c208.c | 480 ++++++++++++++++++++++++++++++++++
 4 files changed, 497 insertions(+)
 create mode 100644 drivers/media/i2c/cat24c208.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 7d9490a5c15a..407d76c42bab 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14912,6 +14912,13 @@ S:	Maintained
 T:	git git://linuxtv.org/media_tree.git
 F:	drivers/media/i2c/ov9734.c
 
+ON SEMICONDUCTOR CAT24C208 EDID EEPROM DRIVER
+M:	Hans Verkuil <hverkuil-cisco@xs4all.nl>
+L:	linux-media@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/media/i2c/onnn,cat24c208.yaml
+F:	drivers/media/i2c/cat24c208*
+
 ONENAND FLASH DRIVER
 M:	Kyungmin Park <kyungmin.park@samsung.com>
 L:	linux-mtd@lists.infradead.org
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 2b20aa6c37b1..2f5f9f058b48 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -1530,6 +1530,15 @@ endmenu
 menu "Miscellaneous helper chips"
 	visible if !MEDIA_HIDE_ANCILLARY_SUBDRV
 
+config VIDEO_CAT24C208
+	tristate "ON Semiconductor cat24c208 EDID EEPROM"
+	depends on VIDEO_DEV && I2C && OF
+	help
+	  Support for the ON Semiconductor CAT24C208 Dual Port EDID EEPROM.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cat24c208.
+
 config VIDEO_I2C
 	tristate "I2C transport video support"
 	depends on VIDEO_DEV && I2C
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index 3e1696963e7f..70e4360a21ba 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_VIDEO_APTINA_PLL) += aptina-pll.o
 obj-$(CONFIG_VIDEO_BT819) += bt819.o
 obj-$(CONFIG_VIDEO_BT856) += bt856.o
 obj-$(CONFIG_VIDEO_BT866) += bt866.o
+obj-$(CONFIG_VIDEO_CAT24C208) += cat24c208.o
 obj-$(CONFIG_VIDEO_CCS) += ccs/
 obj-$(CONFIG_VIDEO_CCS_PLL) += ccs-pll.o
 obj-$(CONFIG_VIDEO_CS3308) += cs3308.o
diff --git a/drivers/media/i2c/cat24c208.c b/drivers/media/i2c/cat24c208.c
new file mode 100644
index 000000000000..63b496f62c19
--- /dev/null
+++ b/drivers/media/i2c/cat24c208.c
@@ -0,0 +1,480 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * HDMI i2c controlled EEPROM from ON Semiconductor or Catalyst Semiconductor
+ *
+ * Support for i2c based DDC EEPROM
+ *
+ * Copyright (C) 2021-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ */
+
+/*
+ * REF_01 - ON Semiconductor, cat24c208, Datasheet, URL : https://www.onsemi.com/pdf/datasheet/cat24c208-d.pdf
+ *	Revision 7, May 2018
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/mod_devicetable.h>
+#include <linux/gpio/consumer.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/workqueue.h>
+
+#include <media/cec-notifier.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-dv-timings.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ioctl.h>
+
+MODULE_DESCRIPTION("cat24c208 EDID EEPROM driver");
+MODULE_AUTHOR("Jonathan Selnes Bognaes <jonathansb1@gmail.com>");
+MODULE_LICENSE("GPL");
+
+/*
+ * CAT24C208 setup
+ */
+#define BYTES_PER_BLOCK		128
+#define EDID_OFFSET_EXT_FLAG	126
+#define MAX_WRITE_BYTES		16
+#define NUM_BLOCKS		4
+#define NUM_CLIENTS		3
+#define CONFIG_NB_BIT		BIT(0)
+#define CONFIG_AB0_BIT		BIT(1)
+#define CONFIG_AB1_BIT		BIT(2)
+#define CONFIG_WE_BIT		BIT(3)
+
+/*
+ * From the datasheet: REF_01
+ *
+ * The write cycle time is the time from a valid stop condition of a write
+ * sequence to the end of the internal program/erase cycle. During the write
+ * cycle, the bus interface circuits are disabled, SDA is allowed to remain
+ * high, and the device does not respond to its slave address.
+ */
+#define WRITE_CYCLE_TIME_US	5000
+
+/*
+ * CAT24C208 addresses
+ */
+#define CONFIG_I2C_ADDR		0x31
+#define EEPROM_I2C_ADDR		0x50
+#define SEGMENT_I2C_ADDR	0x30
+
+struct cat24c208_state {
+	struct i2c_client *dev_client;
+	struct i2c_client *data_client;
+	struct i2c_client *seg_client;
+	// V4L2 ioctl serialization
+	struct mutex lock;
+	struct cec_notifier *notifier;
+	struct delayed_work dwork_enable_hpd;
+
+	struct v4l2_device v4l2_dev;
+	struct video_device vdev;
+	struct gpio_desc *hpd_gpio;
+
+	u8 edid_blocks;		// edid length can vary, one block = 128 bytes
+	u8 edid[BYTES_PER_BLOCK * NUM_BLOCKS]; // actual active edid data
+};
+
+static const struct v4l2_file_operations cat24c208_fops = {
+	.owner		= THIS_MODULE,
+	.open		= v4l2_fh_open,
+	.release	= v4l2_fh_release,
+	.unlocked_ioctl = video_ioctl2,
+};
+
+static int cat24c208_seg_write(struct cat24c208_state *state, u8 *data, u16 len, u8 seg)
+{
+	struct i2c_msg msg[] = {
+		{
+			.addr = state->seg_client->addr,	// Segment
+			.buf = &seg,
+			.len = 1,
+			.flags = 0,
+		},
+		{
+			.addr = state->data_client->addr,	// write data
+			.buf = data,
+			.len = len,
+			.flags = 0,
+		},
+	};
+	int err;
+
+	if (seg)
+		err = i2c_transfer(state->dev_client->adapter, msg, ARRAY_SIZE(msg));
+	else
+		err = i2c_transfer(state->dev_client->adapter, &msg[1], 1);
+
+	if (err < 0)
+		dev_err(&state->dev_client->dev, "Writing to 0x%x failed (segment %d)\n",
+			state->data_client->addr, seg);
+
+	usleep_range(WRITE_CYCLE_TIME_US, 2 * WRITE_CYCLE_TIME_US);
+	return err < 0 ? err : 0;
+}
+
+static int cat24c208_edid_read(struct cat24c208_state *state, u8 *data, u8 seg, u8 offset, u16 len)
+{
+	int err;
+
+	len *= BYTES_PER_BLOCK;
+	if (seg) {
+		struct i2c_msg msg[] = {
+			{
+				.addr = state->seg_client->addr,	// Segment
+				.buf = &seg,
+				.len = 1,
+				.flags = 0,
+			},
+			{
+				.addr = state->data_client->addr,	// read data
+				.buf = data,
+				.len = len,
+				.flags = I2C_M_RD,
+			},
+		};
+		err = i2c_transfer(state->dev_client->adapter, msg, ARRAY_SIZE(msg));
+	} else {
+		struct i2c_msg msg[] = {
+			{
+				.addr = state->data_client->addr,	// set offset
+				.buf = &offset,
+				.len = 1,
+				.flags = 0,
+			},
+			{
+				.addr = state->data_client->addr,	// read data
+				.buf = data,
+				.len = len,
+				.flags = I2C_M_RD,
+			},
+		};
+		err = i2c_transfer(state->dev_client->adapter, msg, ARRAY_SIZE(msg));
+	}
+
+	if (err < 0)
+		dev_err(&state->dev_client->dev, "Reading of EDID failed\n");
+	return err < 0 ? err : 0;
+}
+
+static int cat24c208_set_config(struct i2c_client *client)
+{
+	u8 buf[2] = { 0, CONFIG_NB_BIT };
+	struct i2c_msg msg = {
+		.addr = client->addr,
+		.buf = buf,
+		.len = sizeof(buf),
+		.flags = 0,
+	};
+	int err;
+
+	err = i2c_transfer(client->adapter, &msg, 1);
+	if (err < 0)
+		dev_err(&client->dev, "Could not set config register\n");
+
+	usleep_range(WRITE_CYCLE_TIME_US, 2 * WRITE_CYCLE_TIME_US);
+	return err < 0 ? err : 0;
+}
+
+static bool cat24c208_is_valid_edid(const u8 *block)
+{
+	static const u8 header_pattern[] = {
+		0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
+	};
+
+	return !memcmp(block, header_pattern, sizeof(header_pattern));
+}
+
+static void cat24c208_delayed_work_release_hpd(struct work_struct *work)
+{
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct cat24c208_state *state = container_of(dwork, struct cat24c208_state,
+						     dwork_enable_hpd);
+
+	gpiod_set_value(state->hpd_gpio, 1);
+}
+
+static int cat24c208_set_edid(struct file *file, void *fh, struct v4l2_edid *edid)
+{
+	struct cat24c208_state *state = video_drvdata(file);
+	u8 buf[MAX_WRITE_BYTES + 1];
+	u16 pa;
+	int err;
+	int seg;
+	int i;
+
+	memset(edid->reserved, 0, sizeof(edid->reserved));
+
+	if (edid->pad)
+		return -EINVAL;
+
+	if (edid->blocks > NUM_BLOCKS) {
+		edid->blocks = NUM_BLOCKS;
+		return -E2BIG;
+	}
+
+	if (edid->start_block)
+		return -EINVAL;
+
+	pa = v4l2_get_edid_phys_addr(edid->edid, edid->blocks * BYTES_PER_BLOCK, NULL);
+
+	err = v4l2_phys_addr_validate(pa, NULL, NULL);
+	if (err)
+		return err;
+
+	if (state->hpd_gpio) {
+		cancel_delayed_work_sync(&state->dwork_enable_hpd);
+		gpiod_set_value(state->hpd_gpio, 0);
+	}
+
+	if (edid->blocks == 0) {
+		cec_notifier_set_phys_addr(state->notifier, pa);
+		return 0;
+	}
+
+	state->edid_blocks = edid->blocks;
+	memcpy(state->edid, edid->edid, state->edid_blocks * BYTES_PER_BLOCK);
+
+	/* Write EDID to EEPROM */
+	for (i = 0; i < edid->blocks * BYTES_PER_BLOCK; i = i + MAX_WRITE_BYTES) {
+		if (i >= 2 * BYTES_PER_BLOCK) {
+			seg = 1;
+			buf[0] = i - BYTES_PER_BLOCK * 2;
+		} else {
+			seg = 0;
+			buf[0] = i;
+		}
+
+		memcpy(buf + 1, &edid->edid[i], MAX_WRITE_BYTES);
+		err = cat24c208_seg_write(state, buf, MAX_WRITE_BYTES + 1, seg);
+		if (err) {
+			dev_err(&state->dev_client->dev,
+				"Could not write EDID to EEPROM, i: %d\n", i);
+			return err;
+		}
+	}
+
+	cec_notifier_set_phys_addr(state->notifier, pa);
+
+	if (state->hpd_gpio)
+		schedule_delayed_work(&state->dwork_enable_hpd, 110 * HZ / 1000);
+
+	return 0;
+}
+
+static int cat24c208_get_edid(struct file *file, void *fh, struct v4l2_edid *edid)
+{
+	struct cat24c208_state *state = video_drvdata(file);
+
+	memset(edid->reserved, 0, sizeof(edid->reserved));
+
+	if (edid->pad != 0)
+		return -EINVAL;
+
+	if (edid->start_block == 0 && edid->blocks == 0) {
+		edid->blocks = state->edid_blocks;
+		return 0;
+	}
+
+	if (state->edid_blocks == 0)
+		return -ENODATA;
+
+	if (edid->start_block >= state->edid_blocks)
+		return -EINVAL;
+
+	if (edid->start_block + edid->blocks > state->edid_blocks)
+		edid->blocks = state->edid_blocks - edid->start_block;
+
+	memcpy(edid->edid, state->edid + edid->start_block * BYTES_PER_BLOCK,
+	       edid->blocks * BYTES_PER_BLOCK);
+
+	return 0;
+}
+
+static int cat24c208_get_input(struct file *file, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+
+static int cat24c208_set_input(struct file *file, void *priv, unsigned int i)
+{
+	return i > 0 ? -EINVAL : 0;
+}
+
+static int cat24c208_enum_input(struct file *file, void *priv,
+				struct v4l2_input *inp)
+{
+	if (inp->index)
+		return -EINVAL;
+	strscpy(inp->name, "HDMI", sizeof(inp->name));
+	inp->capabilities = 0;
+	inp->type = V4L2_INPUT_TYPE_CAMERA;
+	return 0;
+}
+
+static int cat24c208_querycap(struct file *file,
+			      void *priv, struct v4l2_capability *cap)
+{
+	struct cat24c208_state *state = video_drvdata(file);
+	struct i2c_client *client = state->dev_client;
+
+	strscpy(cap->driver, "cat24c208", sizeof(cap->driver));
+	strscpy(cap->card, "cat24c208 EDID EEPROM", sizeof(cap->card));
+	snprintf(cap->bus_info, sizeof(cap->bus_info),
+		 "I2C:%d-%04x", client->adapter->nr, client->addr);
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops cat24c208_ioctl_ops = {
+	.vidioc_querycap	= cat24c208_querycap,
+	.vidioc_g_edid		= cat24c208_get_edid,
+	.vidioc_s_edid		= cat24c208_set_edid,
+	.vidioc_g_input		= cat24c208_get_input,
+	.vidioc_s_input		= cat24c208_set_input,
+	.vidioc_enum_input	= cat24c208_enum_input,
+};
+
+static void cat24c208_release(struct video_device *vdev)
+{
+	struct cat24c208_state *state = video_get_drvdata(vdev);
+
+	v4l2_device_unregister(&state->v4l2_dev);
+	mutex_destroy(&state->lock);
+	kfree(state);
+}
+
+static int cat24c208_probe(struct i2c_client *client)
+{
+	struct cat24c208_state *state;
+	struct v4l2_device *v4l2_dev;
+	int blocks;
+	int ret;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	state->dev_client = client;
+	state->data_client = i2c_new_ancillary_device(client, "eeprom", EEPROM_I2C_ADDR);
+	if (IS_ERR(state->data_client)) {
+		ret = PTR_ERR(state->data_client);
+		goto free_state;
+	}
+	state->seg_client = i2c_new_ancillary_device(client, "segment", SEGMENT_I2C_ADDR);
+	if (IS_ERR(state->seg_client)) {
+		ret = PTR_ERR(state->seg_client);
+		goto unreg_i2c_first;
+	}
+
+	ret = cat24c208_set_config(client);
+	if (ret)
+		goto unreg_i2c_all;
+
+	if (cat24c208_edid_read(state, state->edid, 0, 0, 2) >= 0 &&
+	    cat24c208_is_valid_edid(state->edid)) {
+		unsigned int i;
+
+		blocks = 1 + state->edid[EDID_OFFSET_EXT_FLAG];
+		state->edid_blocks = blocks;
+		for (i = 2; i < blocks; i += 2) {
+			if (cat24c208_edid_read(state, state->edid + i * BYTES_PER_BLOCK,
+						i / 2, 0, (i + 1 >= blocks ? 1 : 2))) {
+				state->edid_blocks = i;
+				break;
+			}
+		}
+	}
+
+	v4l2_dev = &state->v4l2_dev;
+	strscpy(v4l2_dev->name, "cat24c208", sizeof(v4l2_dev->name));
+	ret = v4l2_device_register(&client->dev, v4l2_dev);
+	if (ret) {
+		dev_err(&client->dev, "v4l2_device_register failed: %d\n", ret);
+		goto unreg_i2c_all;
+	}
+
+	mutex_init(&state->lock);
+
+	state->notifier = cec_notifier_conn_register(&client->dev, NULL, NULL);
+	if (!state->notifier) {
+		dev_err(&client->dev, "Failed to get CEC notifier\n");
+		ret = -ENOMEM;
+		goto unreg_i2c_all;
+	}
+
+	state->hpd_gpio = devm_gpiod_get_optional(&client->dev,
+						  "hpd", GPIOD_OUT_LOW);
+	if (IS_ERR(state->hpd_gpio)) {
+		ret = PTR_ERR(state->hpd_gpio);
+		dev_err(&client->dev, "Failed to get hpd-gpio err:%d\n", ret);
+		goto unreg_i2c_all;
+	}
+
+	INIT_DELAYED_WORK(&state->dwork_enable_hpd, cat24c208_delayed_work_release_hpd);
+
+	snprintf(state->vdev.name, sizeof(state->vdev.name),
+		 "cat24c208 %d-%d", client->adapter->nr, client->addr);
+
+	state->vdev.v4l2_dev = v4l2_dev;
+	state->vdev.fops = &cat24c208_fops;
+	state->vdev.ioctl_ops = &cat24c208_ioctl_ops;
+	state->vdev.lock = &state->lock;
+	state->vdev.release = cat24c208_release;
+	state->vdev.device_caps = V4L2_CAP_EDID;
+
+	video_set_drvdata(&state->vdev, state);
+	i2c_set_clientdata(client, state);
+	ret = video_register_device(&state->vdev, VFL_TYPE_VIDEO, -1);
+	if (ret != 0) {
+		dev_err(&client->dev, "Video registering failed: %d\n", ret);
+		goto unreg_v4l2_dev;
+	}
+	return 0;
+
+unreg_v4l2_dev:
+	v4l2_device_unregister(&state->v4l2_dev);
+	cec_notifier_conn_unregister(state->notifier);
+	cancel_delayed_work_sync(&state->dwork_enable_hpd);
+unreg_i2c_all:
+	i2c_unregister_device(state->seg_client);
+unreg_i2c_first:
+	i2c_unregister_device(state->data_client);
+free_state:
+	kfree(state);
+	return ret;
+}
+
+static int cat24c208_remove(struct i2c_client *client)
+{
+	struct cat24c208_state *state = i2c_get_clientdata(client);
+
+	cancel_delayed_work_sync(&state->dwork_enable_hpd);
+	cec_notifier_conn_unregister(state->notifier);
+	i2c_unregister_device(state->data_client);
+	i2c_unregister_device(state->seg_client);
+	video_unregister_device(&state->vdev);
+
+	return 0;
+}
+
+static const struct of_device_id cat24c208_of_match[] = {
+	{ .compatible = "onnn,cat24c208"},
+	{}
+};
+MODULE_DEVICE_TABLE(of, cat24c208_of_match);
+
+static struct i2c_driver cat24c208_driver = {
+	.driver = {
+		.name	= "cat24c208",
+		.of_match_table = cat24c208_of_match,
+	},
+	.probe_new	= cat24c208_probe,
+	.remove		= cat24c208_remove,
+};
+module_i2c_driver(cat24c208_driver);
-- 
2.37.3


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 5/5] media: v4l2-dev: handle V4L2_CAP_EDID
  2022-09-28 11:21 [PATCH v3 0/5] Add the cat24c208 EDID EEPROM driver + new EDID capability Erling Ljunggren
                   ` (3 preceding siblings ...)
  2022-09-28 11:21 ` [PATCH v3 4/5] media: i2c: cat24c208: driver for the cat24c208 EDID EEPROM Erling Ljunggren
@ 2022-09-28 11:21 ` Erling Ljunggren
  4 siblings, 0 replies; 9+ messages in thread
From: Erling Ljunggren @ 2022-09-28 11:21 UTC (permalink / raw)
  To: linux-media; +Cc: Erling Ljunggren

When the V4L2_CAP_EDID capability flag is set,
ioctls for enum inputs/outputs and get/set edid are automatically set.

Signed-off-by: Erling Ljunggren <hljunggr@cisco.com>
---
 drivers/media/v4l2-core/v4l2-dev.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index d00237ee4cae..e8222b9835e6 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -556,6 +556,7 @@ static void determine_valid_ioctls(struct video_device *vdev)
 	bool is_rx = vdev->vfl_dir != VFL_DIR_TX;
 	bool is_tx = vdev->vfl_dir != VFL_DIR_RX;
 	bool is_io_mc = vdev->device_caps & V4L2_CAP_IO_MC;
+	bool is_edid =  vdev->device_caps & V4L2_CAP_EDID;
 
 	bitmap_zero(valid_ioctls, BASE_VIDIOC_PRIVATE);
 
@@ -778,6 +779,20 @@ static void determine_valid_ioctls(struct video_device *vdev)
 		SET_VALID_IOCTL(ops, VIDIOC_S_TUNER, vidioc_s_tuner);
 		SET_VALID_IOCTL(ops, VIDIOC_S_HW_FREQ_SEEK, vidioc_s_hw_freq_seek);
 	}
+	if (is_edid) {
+		SET_VALID_IOCTL(ops, VIDIOC_G_EDID, vidioc_g_edid);
+		if (is_tx) {
+			SET_VALID_IOCTL(ops, VIDIOC_G_OUTPUT, vidioc_g_output);
+			SET_VALID_IOCTL(ops, VIDIOC_S_OUTPUT, vidioc_s_output);
+			SET_VALID_IOCTL(ops, VIDIOC_ENUMOUTPUT, vidioc_enum_output);
+		}
+		if (is_rx) {
+			SET_VALID_IOCTL(ops, VIDIOC_ENUMINPUT, vidioc_enum_input);
+			SET_VALID_IOCTL(ops, VIDIOC_G_INPUT, vidioc_g_input);
+			SET_VALID_IOCTL(ops, VIDIOC_S_INPUT, vidioc_s_input);
+			SET_VALID_IOCTL(ops, VIDIOC_S_EDID, vidioc_s_edid);
+		}
+	}
 
 	bitmap_andnot(vdev->valid_ioctls, valid_ioctls, vdev->valid_ioctls,
 			BASE_VIDIOC_PRIVATE);
-- 
2.37.3


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 3/5] dt-bindings: media: add cat24c208 bindings
  2022-09-28 11:21 ` [PATCH v3 3/5] dt-bindings: media: add cat24c208 bindings Erling Ljunggren
@ 2022-09-28 22:37   ` Rob Herring
  2022-09-29 13:26   ` Rob Herring
  1 sibling, 0 replies; 9+ messages in thread
From: Rob Herring @ 2022-09-28 22:37 UTC (permalink / raw)
  To: Erling Ljunggren; +Cc: devicetree, linux-media

On Wed, 28 Sep 2022 13:21:45 +0200, Erling Ljunggren wrote:
> Add devicetree bindings for new cat24c208 EDID EEPROM driver.
> 
> Signed-off-by: Erling Ljunggren <hljunggr@cisco.com>
> ---
>  .../bindings/media/i2c/onnn,cat24c208.yaml    | 48 +++++++++++++++++++
>  1 file changed, 48 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/media/i2c/onnn,cat24c208.yaml
> 

My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):

yamllint warnings/errors:

dtschema/dtc warnings/errors:
Error: Documentation/devicetree/bindings/media/i2c/onnn,cat24c208.example.dts:25.39-40 syntax error
FATAL ERROR: Unable to parse input tree
make[1]: *** [scripts/Makefile.lib:384: Documentation/devicetree/bindings/media/i2c/onnn,cat24c208.example.dtb] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:1420: dt_binding_check] Error 2

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/patch/

This check can fail if there are any dependencies. The base for a patch
series is generally the most recent rc1.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit.


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 3/5] dt-bindings: media: add cat24c208 bindings
  2022-09-28 11:21 ` [PATCH v3 3/5] dt-bindings: media: add cat24c208 bindings Erling Ljunggren
  2022-09-28 22:37   ` Rob Herring
@ 2022-09-29 13:26   ` Rob Herring
  2022-10-04  8:02     ` Erling Ljunggren (hljunggr)
  1 sibling, 1 reply; 9+ messages in thread
From: Rob Herring @ 2022-09-29 13:26 UTC (permalink / raw)
  To: Erling Ljunggren; +Cc: linux-media, devicetree

On Wed, Sep 28, 2022 at 01:21:45PM +0200, Erling Ljunggren wrote:
> Add devicetree bindings for new cat24c208 EDID EEPROM driver.
> 
> Signed-off-by: Erling Ljunggren <hljunggr@cisco.com>
> ---
>  .../bindings/media/i2c/onnn,cat24c208.yaml    | 48 +++++++++++++++++++
>  1 file changed, 48 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/media/i2c/onnn,cat24c208.yaml
> 
> diff --git a/Documentation/devicetree/bindings/media/i2c/onnn,cat24c208.yaml b/Documentation/devicetree/bindings/media/i2c/onnn,cat24c208.yaml
> new file mode 100644
> index 000000000000..fcfaccb5e39f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/i2c/onnn,cat24c208.yaml
> @@ -0,0 +1,48 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/media/i2c/onnn,cat24c208.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: ON Semiconductor CAT24C208 EDID EEPROM driver
> +
> +maintainers:
> +  - Hans Verkuil <hverkuil-cisco@xs4all.nl>
> +
> +description: |
> +  CAT24C208 is a dual port i2c EEPROM designed for EDID storage.
> +
> +
> +properties:
> +  compatible:
> +    const: onnn,cat24c208
> +
> +  reg:
> +    maxItems: 1
> +
> +  hpd-gpios:
> +    maxItems: 1
> +    description:
> +      References to the GPIO that controls the HDMI hot-plug detection pin.
> +      The active flag indicates the GPIO level that enables hot-plug detection.

This node is supposed to represent a device, cat24c208, but that device 
I'm guessing knows nothing about HPD. That's a property of the connector 
and belongs in a connector node much like we have for the other side of 
display connections. It may seem like overkill, but it frequently 
evolves such that not having a connector node becomes a problem. See 
'hdmi-connector' binding for example.

Rob

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 3/5] dt-bindings: media: add cat24c208 bindings
  2022-09-29 13:26   ` Rob Herring
@ 2022-10-04  8:02     ` Erling Ljunggren (hljunggr)
  0 siblings, 0 replies; 9+ messages in thread
From: Erling Ljunggren (hljunggr) @ 2022-10-04  8:02 UTC (permalink / raw)
  To: robh; +Cc: linux-media, devicetree

On Thu, 2022-09-29 at 08:26 -0500, Rob Herring wrote:
> On Wed, Sep 28, 2022 at 01:21:45PM +0200, Erling Ljunggren wrote:
> > Add devicetree bindings for new cat24c208 EDID EEPROM driver.
> > 
> > Signed-off-by: Erling Ljunggren <hljunggr@cisco.com>
> > ---
> >  .../bindings/media/i2c/onnn,cat24c208.yaml    | 48
> > +++++++++++++++++++
> >  1 file changed, 48 insertions(+)
> >  create mode 100644
> > Documentation/devicetree/bindings/media/i2c/onnn,cat24c208.yaml
> > 
> > diff --git
> > a/Documentation/devicetree/bindings/media/i2c/onnn,cat24c208.yaml
> > b/Documentation/devicetree/bindings/media/i2c/onnn,cat24c208.yaml
> > new file mode 100644
> > index 000000000000..fcfaccb5e39f
> > --- /dev/null
> > +++
> > b/Documentation/devicetree/bindings/media/i2c/onnn,cat24c208.yaml
> > @@ -0,0 +1,48 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/media/i2c/onnn,cat24c208.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: ON Semiconductor CAT24C208 EDID EEPROM driver
> > +
> > +maintainers:
> > +  - Hans Verkuil <hverkuil-cisco@xs4all.nl>
> > +
> > +description: |
> > +  CAT24C208 is a dual port i2c EEPROM designed for EDID storage.
> > +
> > +
> > +properties:
> > +  compatible:
> > +    const: onnn,cat24c208
> > +
> > +  reg:
> > +    maxItems: 1
> > +
> > +  hpd-gpios:
> > +    maxItems: 1
> > +    description:
> > +      References to the GPIO that controls the HDMI hot-plug
> > detection pin.
> > +      The active flag indicates the GPIO level that enables hot-
> > plug detection.
> 
> This node is supposed to represent a device, cat24c208, but that
> device 
> I'm guessing knows nothing about HPD. That's a property of the
> connector 
> and belongs in a connector node much like we have for the other side
> of 
> display connections. It may seem like overkill, but it frequently 
> evolves such that not having a connector node becomes a problem. See 
> 'hdmi-connector' binding for example.
> 
> Rob

Is this what you had in mind?

cat24c208: cat24c208@31 {
	compatible = "onnn,cat24c208";
	reg = <0x31>;
	status = "okay";
	connector-phandle = <&hdmi_in_node>;
};

hdmi_in_node: hdmi-in {
	compatible = "hdmi-connector";
	label = "HDMI IN";
	type = "a";
	hpd-gpios = <&pca9554 4 GPIO_ACTIVE_HIGH>;
	port {
		hdmi_in: endpoint {
			remote-endpoint = <&hdmi_out>;
		};
	};
};

- Erling


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2022-10-04  8:03 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-28 11:21 [PATCH v3 0/5] Add the cat24c208 EDID EEPROM driver + new EDID capability Erling Ljunggren
2022-09-28 11:21 ` [PATCH v3 1/5] media: videodev2.h: add V4L2_CAP_EDID Erling Ljunggren
2022-09-28 11:21 ` [PATCH v3 2/5] media: docs: Add V4L2_CAP_EDID Erling Ljunggren
2022-09-28 11:21 ` [PATCH v3 3/5] dt-bindings: media: add cat24c208 bindings Erling Ljunggren
2022-09-28 22:37   ` Rob Herring
2022-09-29 13:26   ` Rob Herring
2022-10-04  8:02     ` Erling Ljunggren (hljunggr)
2022-09-28 11:21 ` [PATCH v3 4/5] media: i2c: cat24c208: driver for the cat24c208 EDID EEPROM Erling Ljunggren
2022-09-28 11:21 ` [PATCH v3 5/5] media: v4l2-dev: handle V4L2_CAP_EDID Erling Ljunggren

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).