Skip to content

Commit

Permalink
media: ipu3-cio2: Add support for instantiating i2c-clients for VCMs
Browse files Browse the repository at this point in the history
Some sensors come with a variable-focus lens where the lens focus is
controller by a VCM (Voice Coil Motor). If there is a VCM for the
lens-focus, and if so which one, is described on the vcm_type field
of the ACPI SSDB table.

These VCMs are a second I2C device listed as an extra I2cSerialBusV2
resource in the same ACPI device as the sensor. The i2c-core-acpi.c
code only instantiates an i2c-client for the first I2cSerialBusV2
resource.

Add support for instantiating an i2c-client for the VCM with
the type of the i2c-client set based on the SSDB vcm_type field.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
  • Loading branch information
Hans de Goede authored and Mauro Carvalho Chehab committed Dec 16, 2021
1 parent fc2c204 commit 68b9bcc
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 2 deletions.
55 changes: 55 additions & 0 deletions drivers/media/pci/intel/ipu3/cio2-bridge.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <linux/acpi.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/pci.h>
#include <linux/property.h>
#include <media/v4l2-fwnode.h>
Expand Down Expand Up @@ -38,6 +39,18 @@ static const struct cio2_property_names prop_names = {
.link_frequencies = "link-frequencies",
};

static const char * const cio2_vcm_types[] = {
"ad5823",
"dw9714",
"ad5816",
"dw9719",
"dw9718",
"dw9806b",
"wv517s",
"lc898122xa",
"lc898212axb",
};

static int cio2_bridge_read_acpi_buffer(struct acpi_device *adev, char *id,
void *data, u32 size)
{
Expand Down Expand Up @@ -134,6 +147,12 @@ static void cio2_bridge_create_fwnode_properties(
sensor->dev_properties[2] = PROPERTY_ENTRY_U32(
sensor->prop_names.orientation,
orientation);
if (sensor->ssdb.vcmtype) {
sensor->vcm_ref[0] =
SOFTWARE_NODE_REFERENCE(&sensor->swnodes[SWNODE_VCM]);
sensor->dev_properties[3] =
PROPERTY_ENTRY_REF_ARRAY("lens-focus", sensor->vcm_ref);
}

sensor->ep_properties[0] = PROPERTY_ENTRY_U32(
sensor->prop_names.bus_type,
Expand Down Expand Up @@ -195,6 +214,33 @@ static void cio2_bridge_create_connection_swnodes(struct cio2_bridge *bridge,
sensor->node_names.endpoint,
&nodes[SWNODE_CIO2_PORT],
sensor->cio2_properties);
if (sensor->ssdb.vcmtype)
nodes[SWNODE_VCM] =
NODE_VCM(cio2_vcm_types[sensor->ssdb.vcmtype - 1]);
}

static void cio2_bridge_instantiate_vcm_i2c_client(struct cio2_sensor *sensor)
{
struct i2c_board_info board_info = { };
char name[16];

if (!sensor->ssdb.vcmtype)
return;

snprintf(name, sizeof(name), "%s-VCM", acpi_dev_name(sensor->adev));
board_info.dev_name = name;
strscpy(board_info.type, cio2_vcm_types[sensor->ssdb.vcmtype - 1],
ARRAY_SIZE(board_info.type));
board_info.swnode = &sensor->swnodes[SWNODE_VCM];

sensor->vcm_i2c_client =
i2c_acpi_new_device_by_fwnode(acpi_fwnode_handle(sensor->adev),
1, &board_info);
if (IS_ERR(sensor->vcm_i2c_client)) {
dev_warn(&sensor->adev->dev, "Error instantiation VCM i2c-client: %ld\n",
PTR_ERR(sensor->vcm_i2c_client));
sensor->vcm_i2c_client = NULL;
}
}

static void cio2_bridge_unregister_sensors(struct cio2_bridge *bridge)
Expand All @@ -207,6 +253,7 @@ static void cio2_bridge_unregister_sensors(struct cio2_bridge *bridge)
software_node_unregister_nodes(sensor->swnodes);
ACPI_FREE(sensor->pld);
acpi_dev_put(sensor->adev);
i2c_unregister_device(sensor->vcm_i2c_client);
}
}

Expand Down Expand Up @@ -239,6 +286,12 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg,
if (ret)
goto err_put_adev;

if (sensor->ssdb.vcmtype > ARRAY_SIZE(cio2_vcm_types)) {
dev_warn(&adev->dev, "Unknown VCM type %d\n",
sensor->ssdb.vcmtype);
sensor->ssdb.vcmtype = 0;
}

status = acpi_get_physical_device_location(adev->handle, &sensor->pld);
if (ACPI_FAILURE(status)) {
ret = -ENODEV;
Expand Down Expand Up @@ -269,6 +322,8 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg,
sensor->adev = acpi_dev_get(adev);
adev->fwnode.secondary = fwnode;

cio2_bridge_instantiate_vcm_i2c_client(sensor);

dev_info(&cio2->dev, "Found supported sensor %s\n",
acpi_dev_name(adev));

Expand Down
16 changes: 14 additions & 2 deletions drivers/media/pci/intel/ipu3/cio2-bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

#include "ipu3-cio2.h"

struct i2c_client;

#define CIO2_HID "INT343E"
#define CIO2_MAX_LANES 4
#define MAX_NUM_LINK_FREQS 3
Expand Down Expand Up @@ -42,12 +44,19 @@
.properties = _PROPS, \
}

#define NODE_VCM(_TYPE) \
(const struct software_node) { \
.name = _TYPE, \
}

enum cio2_sensor_swnodes {
SWNODE_SENSOR_HID,
SWNODE_SENSOR_PORT,
SWNODE_SENSOR_ENDPOINT,
SWNODE_CIO2_PORT,
SWNODE_CIO2_ENDPOINT,
/* Must be last because it is optional / maybe empty */
SWNODE_VCM,
SWNODE_COUNT
};

Expand Down Expand Up @@ -106,19 +115,22 @@ struct cio2_sensor_config {
struct cio2_sensor {
char name[ACPI_ID_LEN];
struct acpi_device *adev;
struct i2c_client *vcm_i2c_client;

struct software_node swnodes[6];
/* SWNODE_COUNT + 1 for terminating empty node */
struct software_node swnodes[SWNODE_COUNT + 1];
struct cio2_node_names node_names;

struct cio2_sensor_ssdb ssdb;
struct acpi_pld_info *pld;

struct cio2_property_names prop_names;
struct property_entry ep_properties[5];
struct property_entry dev_properties[4];
struct property_entry dev_properties[5];
struct property_entry cio2_properties[3];
struct software_node_ref_args local_ref[1];
struct software_node_ref_args remote_ref[1];
struct software_node_ref_args vcm_ref[1];
};

struct cio2_bridge {
Expand Down

0 comments on commit 68b9bcc

Please sign in to comment.