From: Jacopo Mondi <jacopo+renesas@jmondi.org>
To: kieran.bingham+renesas@ideasonboard.com,
laurent.pinchart@ideasonboard.com, niklas.soderlund@ragnatech.se
Cc: Jacopo Mondi <jacopo+renesas@jmondi.org>,
linux-renesas-soc@vger.kernel.org
Subject: [RFC 10/11] WIP: media: i2c: rdacm20: Add RDACM21 support
Date: Mon, 16 Dec 2019 18:16:19 +0100 [thread overview]
Message-ID: <20191216171620.372683-11-jacopo+renesas@jmondi.org> (raw)
In-Reply-To: <20191216171620.372683-1-jacopo+renesas@jmondi.org>
Add support to the rdacm20 driver for the RDACM21 camera module.
The RDACM21 camera modules includes a max9271 serializer, an OV490 ISP
in conjuction with an OV10640 imager.
This patch implements partial support, up to the point where
communications with the ISP chip are verified.
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
---
.../bindings/media/i2c/imi,rdacm20.yaml | 5 +-
drivers/media/i2c/rdacm20.c | 183 +++++++++++++++---
2 files changed, 156 insertions(+), 32 deletions(-)
diff --git a/Documentation/devicetree/bindings/media/i2c/imi,rdacm20.yaml b/Documentation/devicetree/bindings/media/i2c/imi,rdacm20.yaml
index 76740e285f44..18f8d1fbdbae 100644
--- a/Documentation/devicetree/bindings/media/i2c/imi,rdacm20.yaml
+++ b/Documentation/devicetree/bindings/media/i2c/imi,rdacm20.yaml
@@ -48,7 +48,10 @@ properties:
const: 0
compatible:
- const: imi,rdacm20
+ items:
+ - enum:
+ - imi,rdacm20
+ - imi,rdacm21
reg:
description: -|
diff --git a/drivers/media/i2c/rdacm20.c b/drivers/media/i2c/rdacm20.c
index 1a9c8d1f9484..0431bbb5cbd3 100644
--- a/drivers/media/i2c/rdacm20.c
+++ b/drivers/media/i2c/rdacm20.c
@@ -20,6 +20,7 @@
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/module.h>
+#include <linux/of_device.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
@@ -33,6 +34,10 @@
#define RDACM20_SENSOR_HARD_RESET
#define OV10635_I2C_ADDRESS 0x30
+#define ATTINY85_I2C_ADDRESS 0x50
+
+#define OV10640_I2C_ADDRESS 0x30
+#define OV490_I2C_ADDRESS 0x24
#define OV10635_SOFTWARE_RESET 0x0103
#define OV10635_PID 0x300a
@@ -46,15 +51,29 @@
#define OV10635_FORMAT MEDIA_BUS_FMT_UYVY8_2X8
/* #define OV10635_FORMAT MEDIA_BUS_FMT_UYVY10_2X10 */
+#define OV490_PID 0x300a
+#define OV490_VER 0x300b
+#define OV490_ID_VAL 0x0490
+#define OV490_ID(_p, _v) ((_p) << 8 | (_v) & 0xff)
+
+struct rdacm_data;
+
struct rdacm20_device {
struct device *dev;
struct max9271_device *serializer;
struct i2c_client *sensor;
+ const struct rdacm_data *data;
struct v4l2_subdev sd;
struct media_pad pad;
struct v4l2_ctrl_handler ctrls;
};
+struct rdacm_data {
+ char *devname;
+ int (*sensor_probe)(struct rdacm20_device *dev);
+ unsigned int default_addrs[2];
+};
+
static inline struct rdacm20_device *sd_to_rdacm20(struct v4l2_subdev *sd)
{
return container_of(sd, struct rdacm20_device, sd);
@@ -181,8 +200,9 @@ static struct v4l2_subdev_ops rdacm20_subdev_ops = {
.pad = &rdacm20_subdev_pad_ops,
};
-static int rdacm20_initialize(struct rdacm20_device *dev)
+static int rdacm20_sensor_probe(struct rdacm20_device *dev)
{
+ const struct rdacm_data *data = dev->data;
u32 addrs[2];
int ret;
@@ -193,34 +213,7 @@ static int rdacm20_initialize(struct rdacm20_device *dev)
return -EINVAL;
}
- /*
- * FIXME: The MAX9271 boots at a default address that we will change to
- * the address specified in DT. Set the client address back to the
- * default for initial communication.
- */
-
- /* Create a dummy device, configure to that device, then change the
- * address. Then delete it when the address is changed?
- */
- dev->serializer->client->addr = MAX9271_DEFAULT_ADDR;
-
- /* Verify communication with the MAX9271: ping to wakeup. */
- i2c_smbus_read_byte(dev->serializer->client);
-
- /*
- * Ensure that we have a good link configuration before attempting to
- * identify the device.
- */
- max9271_configure_i2c(dev->serializer);
- max9271_configure_gmsl_link(dev->serializer);
-
- ret = max9271_verify_id(dev->serializer);
- if (ret < 0)
- return ret;
-
- ret = max9271_set_address(dev->serializer, addrs[0]);
- if (ret < 0)
- return ret;
+ dev->sensor->addr = data->default_addrs[0];
/* Reset and verify communication with the OV10635. */
#ifdef RDACM20_SENSOR_HARD_RESET
@@ -271,6 +264,106 @@ static int rdacm20_initialize(struct rdacm20_device *dev)
ARRAY_SIZE(ov10635_regs_wizard));
}
+static int rdacm21_sensor_probe(struct rdacm20_device *dev)
+{
+ const struct rdacm_data *data = dev->data;
+ u32 addrs[2];
+ u8 pid, ver;
+ int ret;
+
+ ret = of_property_read_u32_array(dev->dev->of_node, "reg",
+ addrs, ARRAY_SIZE(addrs));
+ if (ret < 0) {
+ dev_err(dev->dev, "Invalid DT reg property\n");
+ return -EINVAL;
+ }
+
+ /* Verify communications with OV490 by reading its product ID. */
+ dev->sensor->addr = data->default_addrs[1];
+ ret = ov10635_write(dev, 0xfffd, 0x80);
+ if (ret)
+ return ret;
+
+ ret = ov10635_write(dev, 0xfffe, 0x80);
+ if (ret)
+ return ret;
+
+ ret = ov10635_read16(dev, OV490_PID);
+ if (ret < 0) {
+ dev_err(dev->dev, "OV490 PID read failed (%d)\n", ret);
+ return ret;
+ }
+ pid = ret;
+
+ ret = ov10635_read16(dev, OV490_VER);
+ if (ret < 0) {
+ dev_err(dev->dev, "OV490 VERSION read failed (%d)\n", ret);
+ return ret;
+ }
+ ver = ret;
+
+ if (OV490_ID(pid, ver) != OV490_ID_VAL) {
+ dev_dbg(dev->dev, "OV490 ID mismatch: (0x%04x)\n",
+ OV490_ID(pid, ver));
+ return -ENODEV;
+ }
+
+ dev_info(dev->dev, "Identified MAX9271 + OV490 + OV10640 device\n");
+
+ /*
+ * TODO: program MAX9271 to perform address translation to talk with
+ * OV490 from the SoC side.
+ */
+
+ return 0;
+}
+
+static int rdacm20_initialize(struct rdacm20_device *dev)
+{
+ u32 addrs[2];
+ int ret;
+
+ ret = of_property_read_u32_array(dev->dev->of_node, "reg",
+ addrs, ARRAY_SIZE(addrs));
+ if (ret < 0) {
+ dev_err(dev->dev, "Invalid DT reg property\n");
+ return -EINVAL;
+ }
+
+ /*
+ * FIXME: The MAX9271 boots at a default address that we will change to
+ * the address specified in DT. Set the client address back to the
+ * default for initial communication.
+ */
+
+ /* Create a dummy device, configure to that device, then change the
+ * address. Then delete it when the address is changed?
+ */
+ dev->serializer->client->addr = MAX9271_DEFAULT_ADDR;
+
+ /* Verify communication with the MAX9271: ping to wakeup. */
+ i2c_smbus_read_byte(dev->serializer->client);
+
+ /*
+ * Ensure that we have a good link configuration before attempting to
+ * identify the device.
+ */
+ max9271_configure_gmsl_link(dev->serializer);
+ max9271_configure_i2c(dev->serializer);
+
+ ret = max9271_verify_id(dev->serializer);
+ if (ret < 0)
+ return ret;
+
+ ret = max9271_set_address(dev->serializer, addrs[0]);
+ if (ret < 0)
+ return ret;
+
+ return dev->data->sensor_probe(dev);
+
+ return 0;
+}
+
static int rdacm20_probe(struct i2c_client *client)
{
struct rdacm20_device *dev;
@@ -282,6 +375,9 @@ static int rdacm20_probe(struct i2c_client *client)
return -ENOMEM;
dev->dev = &client->dev;
+
+ dev->data = of_device_get_match_data(&client->dev);
+
dev->serializer = devm_kzalloc(&client->dev, sizeof(*dev->serializer),
GFP_KERNEL);
if (!dev->serializer)
@@ -289,7 +385,10 @@ static int rdacm20_probe(struct i2c_client *client)
dev->serializer->client = client;
- /* Create the dummy I2C client for the sensor. */
+ /*
+ * Create the dummy I2C client for the sensor: the right i2c address
+ * will be overwritten later at sensor initialization time.
+ */
dev->sensor = i2c_new_dummy(client->adapter, OV10635_I2C_ADDRESS);
if (!dev->sensor) {
ret = -ENXIO;
@@ -303,6 +402,9 @@ static int rdacm20_probe(struct i2c_client *client)
/* Initialize and register the subdevice. */
v4l2_i2c_subdev_init(&dev->sd, client, &rdacm20_subdev_ops);
+ snprintf(dev->sd.name, sizeof(dev->sd.name), "%s %d-%04x",
+ dev->data->devname, i2c_adapter_id(dev->sensor->adapter),
+ dev->sensor->addr);
dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
v4l2_ctrl_handler_init(&dev->ctrls, 1);
@@ -375,8 +477,27 @@ static void rdacm20_shutdown(struct i2c_client *client)
rdacm20_s_stream(&dev->sd, 0);
}
+struct rdacm_data rdacm20_data = {
+ .devname = "rdacm20",
+ .sensor_probe = rdacm20_sensor_probe,
+ .default_addrs = {
+ OV10635_I2C_ADDRESS,
+ ATTINY85_I2C_ADDRESS,
+ },
+};
+
+struct rdacm_data rdacm21_data = {
+ .devname = "rdacm21",
+ .sensor_probe = rdacm21_sensor_probe,
+ .default_addrs = {
+ OV10635_I2C_ADDRESS,
+ OV490_I2C_ADDRESS,
+ },
+};
+
static const struct of_device_id rdacm20_of_ids[] = {
- { .compatible = "imi,rdacm20", },
+ { .compatible = "imi,rdacm20", .data = &rdacm20_data },
+ { .compatible = "imi,rdacm21", .data = &rdacm21_data },
{ }
};
MODULE_DEVICE_TABLE(of, rdacm20_of_ids);
--
2.24.0
next prev parent reply other threads:[~2019-12-16 17:14 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-12-16 17:16 [RFC 00/11] GMSL: Initial RDACM21 support Jacopo Mondi
2019-12-16 17:16 ` [RFC 01/11] fixup! DNI: Debug Jacopo Mondi
2019-12-16 22:34 ` Kieran Bingham
2019-12-16 17:16 ` [RFC 02/11] fixup! arm64: dts: renesas: salvator-x: Add MAX9286 expansion board Jacopo Mondi
2019-12-16 22:37 ` Kieran Bingham
2019-12-16 17:16 ` [RFC 03/11] fixup! arm64: dts: renesas: eagle: Provide Eagle FAKRA dynamic overlay Jacopo Mondi
2019-12-16 22:40 ` Kieran Bingham
2019-12-16 17:16 ` [RFC 04/11] fixup! arm64: dts: renesas: eagle: Provide MAX9286 GMSL deserialiser Jacopo Mondi
2019-12-16 22:41 ` Kieran Bingham
2019-12-16 17:16 ` [RFC 05/11] fixup! dt-bindings: media: i2c: Add bindings for IMI RDACM20 Jacopo Mondi
2019-12-16 22:42 ` Laurent Pinchart
2020-02-14 9:07 ` Kieran Bingham
2019-12-16 17:16 ` [RFC 06/11] media: i2c: Break out max9271 from rdacm20 driver Jacopo Mondi
2019-12-16 17:16 ` [RFC 07/11] media: i2c: max9286: Move notifiers operations Jacopo Mondi
2019-12-16 17:16 ` [RFC 08/11] media: i2c: max9286: Move link setup to completion Jacopo Mondi
2019-12-16 17:16 ` [RFC 09/11] media: i2c: max9286: Expand reverse chanenl amplitude Jacopo Mondi
2019-12-16 17:16 ` Jacopo Mondi [this message]
2019-12-16 17:16 ` [RFC 11/11] arm64: boot: dts: Eagle: Enable RDACM21 Jacopo Mondi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20191216171620.372683-11-jacopo+renesas@jmondi.org \
--to=jacopo+renesas@jmondi.org \
--cc=kieran.bingham+renesas@ideasonboard.com \
--cc=laurent.pinchart@ideasonboard.com \
--cc=linux-renesas-soc@vger.kernel.org \
--cc=niklas.soderlund@ragnatech.se \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).