mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-16 23:45:31 +08:00
media: ipu3-cio2: rename cio2 bridge to ipu bridge and move out of ipu3
cio2 bridge was involved along with IPU3. However, in fact all Intel IPUs besides IPU3 CIO2 need this bridge driver. This patch move bridge driver out of ipu3 directory and rename as ipu-bridge. Then it can be worked with IPU3 and other Intel IPUs. Signed-off-by: Bingbu Cao <bingbu.cao@intel.com> Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
This commit is contained in:
parent
71e8d6e4ae
commit
881ca25978
@ -73,7 +73,7 @@ config VIDEO_PCI_SKELETON
|
||||
Enable build of the skeleton PCI driver, used as a reference
|
||||
when developing new drivers.
|
||||
|
||||
source "drivers/media/pci/intel/ipu3/Kconfig"
|
||||
source "drivers/media/pci/intel/Kconfig"
|
||||
|
||||
endif #MEDIA_PCI_SUPPORT
|
||||
endif #PCI
|
||||
|
21
drivers/media/pci/intel/Kconfig
Normal file
21
drivers/media/pci/intel/Kconfig
Normal file
@ -0,0 +1,21 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
config IPU_BRIDGE
|
||||
bool "Intel IPU Sensors Bridge"
|
||||
depends on VIDEO_IPU3_CIO2 && ACPI
|
||||
depends on I2C
|
||||
help
|
||||
This extension provides an API for the Intel IPU driver to create
|
||||
connections to cameras that are hidden in the SSDB buffer in ACPI.
|
||||
It can be used to enable support for cameras in detachable / hybrid
|
||||
devices that ship with Windows.
|
||||
|
||||
Say Y here if your device is a detachable / hybrid laptop that comes
|
||||
with Windows installed by the OEM, for example:
|
||||
|
||||
- Microsoft Surface models (except Surface Pro 3)
|
||||
- The Lenovo Miix line (for example the 510, 520, 710 and 720)
|
||||
- Dell 7285
|
||||
|
||||
If in doubt, say N here.
|
||||
|
||||
source "drivers/media/pci/intel/ipu3/Kconfig"
|
@ -1,6 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# Makefile for the IPU3 cio2 and ImGU drivers
|
||||
# Makefile for the IPU drivers
|
||||
#
|
||||
|
||||
obj-$(CONFIG_IPU_BRIDGE) += ipu-bridge.o
|
||||
obj-y += ipu3/
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include <linux/property.h>
|
||||
#include <media/v4l2-fwnode.h>
|
||||
|
||||
#include "cio2-bridge.h"
|
||||
#include "ipu-bridge.h"
|
||||
|
||||
/*
|
||||
* Extend this array with ACPI Hardware IDs of devices known to be working
|
||||
@ -20,26 +20,26 @@
|
||||
*
|
||||
* Do not add an entry for a sensor that is not actually supported.
|
||||
*/
|
||||
static const struct cio2_sensor_config cio2_supported_sensors[] = {
|
||||
static const struct ipu_sensor_config ipu_supported_sensors[] = {
|
||||
/* Omnivision OV5693 */
|
||||
CIO2_SENSOR_CONFIG("INT33BE", 1, 419200000),
|
||||
IPU_SENSOR_CONFIG("INT33BE", 1, 419200000),
|
||||
/* Omnivision OV8865 */
|
||||
CIO2_SENSOR_CONFIG("INT347A", 1, 360000000),
|
||||
IPU_SENSOR_CONFIG("INT347A", 1, 360000000),
|
||||
/* Omnivision OV7251 */
|
||||
CIO2_SENSOR_CONFIG("INT347E", 1, 319200000),
|
||||
IPU_SENSOR_CONFIG("INT347E", 1, 319200000),
|
||||
/* Omnivision OV2680 */
|
||||
CIO2_SENSOR_CONFIG("OVTI2680", 0),
|
||||
IPU_SENSOR_CONFIG("OVTI2680", 0),
|
||||
/* Omnivision ov8856 */
|
||||
CIO2_SENSOR_CONFIG("OVTI8856", 3, 180000000, 360000000, 720000000),
|
||||
IPU_SENSOR_CONFIG("OVTI8856", 3, 180000000, 360000000, 720000000),
|
||||
/* Omnivision ov2740 */
|
||||
CIO2_SENSOR_CONFIG("INT3474", 1, 360000000),
|
||||
IPU_SENSOR_CONFIG("INT3474", 1, 360000000),
|
||||
/* Hynix hi556 */
|
||||
CIO2_SENSOR_CONFIG("INT3537", 1, 437000000),
|
||||
IPU_SENSOR_CONFIG("INT3537", 1, 437000000),
|
||||
/* Omnivision ov13b10 */
|
||||
CIO2_SENSOR_CONFIG("OVTIDB10", 1, 560000000),
|
||||
IPU_SENSOR_CONFIG("OVTIDB10", 1, 560000000),
|
||||
};
|
||||
|
||||
static const struct cio2_property_names prop_names = {
|
||||
static const struct ipu_property_names prop_names = {
|
||||
.clock_frequency = "clock-frequency",
|
||||
.rotation = "rotation",
|
||||
.orientation = "orientation",
|
||||
@ -49,7 +49,7 @@ static const struct cio2_property_names prop_names = {
|
||||
.link_frequencies = "link-frequencies",
|
||||
};
|
||||
|
||||
static const char * const cio2_vcm_types[] = {
|
||||
static const char * const ipu_vcm_types[] = {
|
||||
"ad5823",
|
||||
"dw9714",
|
||||
"ad5816",
|
||||
@ -61,8 +61,8 @@ static const char * const cio2_vcm_types[] = {
|
||||
"lc898212axb",
|
||||
};
|
||||
|
||||
static int cio2_bridge_read_acpi_buffer(struct acpi_device *adev, char *id,
|
||||
void *data, u32 size)
|
||||
static int ipu_bridge_read_acpi_buffer(struct acpi_device *adev, char *id,
|
||||
void *data, u32 size)
|
||||
{
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
union acpi_object *obj;
|
||||
@ -98,12 +98,12 @@ out_free_buff:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 cio2_bridge_parse_rotation(struct cio2_sensor *sensor)
|
||||
static u32 ipu_bridge_parse_rotation(struct ipu_sensor *sensor)
|
||||
{
|
||||
switch (sensor->ssdb.degree) {
|
||||
case CIO2_SENSOR_ROTATION_NORMAL:
|
||||
case IPU_SENSOR_ROTATION_NORMAL:
|
||||
return 0;
|
||||
case CIO2_SENSOR_ROTATION_INVERTED:
|
||||
case IPU_SENSOR_ROTATION_INVERTED:
|
||||
return 180;
|
||||
default:
|
||||
dev_warn(&sensor->adev->dev,
|
||||
@ -113,7 +113,7 @@ static u32 cio2_bridge_parse_rotation(struct cio2_sensor *sensor)
|
||||
}
|
||||
}
|
||||
|
||||
static enum v4l2_fwnode_orientation cio2_bridge_parse_orientation(struct cio2_sensor *sensor)
|
||||
static enum v4l2_fwnode_orientation ipu_bridge_parse_orientation(struct ipu_sensor *sensor)
|
||||
{
|
||||
switch (sensor->pld->panel) {
|
||||
case ACPI_PLD_PANEL_FRONT:
|
||||
@ -132,20 +132,20 @@ static enum v4l2_fwnode_orientation cio2_bridge_parse_orientation(struct cio2_se
|
||||
}
|
||||
}
|
||||
|
||||
static void cio2_bridge_create_fwnode_properties(
|
||||
struct cio2_sensor *sensor,
|
||||
struct cio2_bridge *bridge,
|
||||
const struct cio2_sensor_config *cfg)
|
||||
static void ipu_bridge_create_fwnode_properties(
|
||||
struct ipu_sensor *sensor,
|
||||
struct ipu_bridge *bridge,
|
||||
const struct ipu_sensor_config *cfg)
|
||||
{
|
||||
u32 rotation;
|
||||
enum v4l2_fwnode_orientation orientation;
|
||||
|
||||
rotation = cio2_bridge_parse_rotation(sensor);
|
||||
orientation = cio2_bridge_parse_orientation(sensor);
|
||||
rotation = ipu_bridge_parse_rotation(sensor);
|
||||
orientation = ipu_bridge_parse_orientation(sensor);
|
||||
|
||||
sensor->prop_names = prop_names;
|
||||
|
||||
sensor->local_ref[0] = SOFTWARE_NODE_REFERENCE(&sensor->swnodes[SWNODE_CIO2_ENDPOINT]);
|
||||
sensor->local_ref[0] = SOFTWARE_NODE_REFERENCE(&sensor->swnodes[SWNODE_IPU_ENDPOINT]);
|
||||
sensor->remote_ref[0] = SOFTWARE_NODE_REFERENCE(&sensor->swnodes[SWNODE_SENSOR_ENDPOINT]);
|
||||
|
||||
sensor->dev_properties[0] = PROPERTY_ENTRY_U32(
|
||||
@ -181,16 +181,16 @@ static void cio2_bridge_create_fwnode_properties(
|
||||
cfg->link_freqs,
|
||||
cfg->nr_link_freqs);
|
||||
|
||||
sensor->cio2_properties[0] = PROPERTY_ENTRY_U32_ARRAY_LEN(
|
||||
sensor->ipu_properties[0] = PROPERTY_ENTRY_U32_ARRAY_LEN(
|
||||
sensor->prop_names.data_lanes,
|
||||
bridge->data_lanes,
|
||||
sensor->ssdb.lanes);
|
||||
sensor->cio2_properties[1] = PROPERTY_ENTRY_REF_ARRAY(
|
||||
sensor->ipu_properties[1] = PROPERTY_ENTRY_REF_ARRAY(
|
||||
sensor->prop_names.remote_endpoint,
|
||||
sensor->remote_ref);
|
||||
}
|
||||
|
||||
static void cio2_bridge_init_swnode_names(struct cio2_sensor *sensor)
|
||||
static void ipu_bridge_init_swnode_names(struct ipu_sensor *sensor)
|
||||
{
|
||||
snprintf(sensor->node_names.remote_port,
|
||||
sizeof(sensor->node_names.remote_port),
|
||||
@ -203,26 +203,26 @@ static void cio2_bridge_init_swnode_names(struct cio2_sensor *sensor)
|
||||
SWNODE_GRAPH_ENDPOINT_NAME_FMT, 0); /* And endpoint 0 */
|
||||
}
|
||||
|
||||
static void cio2_bridge_init_swnode_group(struct cio2_sensor *sensor)
|
||||
static void ipu_bridge_init_swnode_group(struct ipu_sensor *sensor)
|
||||
{
|
||||
struct software_node *nodes = sensor->swnodes;
|
||||
|
||||
sensor->group[SWNODE_SENSOR_HID] = &nodes[SWNODE_SENSOR_HID];
|
||||
sensor->group[SWNODE_SENSOR_PORT] = &nodes[SWNODE_SENSOR_PORT];
|
||||
sensor->group[SWNODE_SENSOR_ENDPOINT] = &nodes[SWNODE_SENSOR_ENDPOINT];
|
||||
sensor->group[SWNODE_CIO2_PORT] = &nodes[SWNODE_CIO2_PORT];
|
||||
sensor->group[SWNODE_CIO2_ENDPOINT] = &nodes[SWNODE_CIO2_ENDPOINT];
|
||||
sensor->group[SWNODE_IPU_PORT] = &nodes[SWNODE_IPU_PORT];
|
||||
sensor->group[SWNODE_IPU_ENDPOINT] = &nodes[SWNODE_IPU_ENDPOINT];
|
||||
if (sensor->ssdb.vcmtype)
|
||||
sensor->group[SWNODE_VCM] = &nodes[SWNODE_VCM];
|
||||
}
|
||||
|
||||
static void cio2_bridge_create_connection_swnodes(struct cio2_bridge *bridge,
|
||||
struct cio2_sensor *sensor)
|
||||
static void ipu_bridge_create_connection_swnodes(struct ipu_bridge *bridge,
|
||||
struct ipu_sensor *sensor)
|
||||
{
|
||||
struct software_node *nodes = sensor->swnodes;
|
||||
char vcm_name[ACPI_ID_LEN + 4];
|
||||
|
||||
cio2_bridge_init_swnode_names(sensor);
|
||||
ipu_bridge_init_swnode_names(sensor);
|
||||
|
||||
nodes[SWNODE_SENSOR_HID] = NODE_SENSOR(sensor->name,
|
||||
sensor->dev_properties);
|
||||
@ -232,24 +232,24 @@ static void cio2_bridge_create_connection_swnodes(struct cio2_bridge *bridge,
|
||||
sensor->node_names.endpoint,
|
||||
&nodes[SWNODE_SENSOR_PORT],
|
||||
sensor->ep_properties);
|
||||
nodes[SWNODE_CIO2_PORT] = NODE_PORT(sensor->node_names.remote_port,
|
||||
&bridge->cio2_hid_node);
|
||||
nodes[SWNODE_CIO2_ENDPOINT] = NODE_ENDPOINT(
|
||||
nodes[SWNODE_IPU_PORT] = NODE_PORT(sensor->node_names.remote_port,
|
||||
&bridge->ipu_hid_node);
|
||||
nodes[SWNODE_IPU_ENDPOINT] = NODE_ENDPOINT(
|
||||
sensor->node_names.endpoint,
|
||||
&nodes[SWNODE_CIO2_PORT],
|
||||
sensor->cio2_properties);
|
||||
&nodes[SWNODE_IPU_PORT],
|
||||
sensor->ipu_properties);
|
||||
if (sensor->ssdb.vcmtype) {
|
||||
/* append ssdb.link to distinguish VCM nodes with same HID */
|
||||
snprintf(vcm_name, sizeof(vcm_name), "%s-%u",
|
||||
cio2_vcm_types[sensor->ssdb.vcmtype - 1],
|
||||
ipu_vcm_types[sensor->ssdb.vcmtype - 1],
|
||||
sensor->ssdb.link);
|
||||
nodes[SWNODE_VCM] = NODE_VCM(vcm_name);
|
||||
}
|
||||
|
||||
cio2_bridge_init_swnode_group(sensor);
|
||||
ipu_bridge_init_swnode_group(sensor);
|
||||
}
|
||||
|
||||
static void cio2_bridge_instantiate_vcm_i2c_client(struct cio2_sensor *sensor)
|
||||
static void ipu_bridge_instantiate_vcm_i2c_client(struct ipu_sensor *sensor)
|
||||
{
|
||||
struct i2c_board_info board_info = { };
|
||||
char name[16];
|
||||
@ -259,7 +259,7 @@ static void cio2_bridge_instantiate_vcm_i2c_client(struct cio2_sensor *sensor)
|
||||
|
||||
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],
|
||||
strscpy(board_info.type, ipu_vcm_types[sensor->ssdb.vcmtype - 1],
|
||||
ARRAY_SIZE(board_info.type));
|
||||
board_info.swnode = &sensor->swnodes[SWNODE_VCM];
|
||||
|
||||
@ -273,9 +273,9 @@ static void cio2_bridge_instantiate_vcm_i2c_client(struct cio2_sensor *sensor)
|
||||
}
|
||||
}
|
||||
|
||||
static void cio2_bridge_unregister_sensors(struct cio2_bridge *bridge)
|
||||
static void ipu_bridge_unregister_sensors(struct ipu_bridge *bridge)
|
||||
{
|
||||
struct cio2_sensor *sensor;
|
||||
struct ipu_sensor *sensor;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < bridge->n_sensors; i++) {
|
||||
@ -287,12 +287,12 @@ static void cio2_bridge_unregister_sensors(struct cio2_bridge *bridge)
|
||||
}
|
||||
}
|
||||
|
||||
static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg,
|
||||
struct cio2_bridge *bridge,
|
||||
struct pci_dev *cio2)
|
||||
static int ipu_bridge_connect_sensor(const struct ipu_sensor_config *cfg,
|
||||
struct ipu_bridge *bridge,
|
||||
struct pci_dev *ipu)
|
||||
{
|
||||
struct fwnode_handle *fwnode, *primary;
|
||||
struct cio2_sensor *sensor;
|
||||
struct ipu_sensor *sensor;
|
||||
struct acpi_device *adev;
|
||||
acpi_status status;
|
||||
int ret;
|
||||
@ -303,22 +303,22 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg,
|
||||
|
||||
if (bridge->n_sensors >= CIO2_NUM_PORTS) {
|
||||
acpi_dev_put(adev);
|
||||
dev_err(&cio2->dev, "Exceeded available CIO2 ports\n");
|
||||
dev_err(&ipu->dev, "Exceeded available IPU ports\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sensor = &bridge->sensors[bridge->n_sensors];
|
||||
|
||||
ret = cio2_bridge_read_acpi_buffer(adev, "SSDB",
|
||||
&sensor->ssdb,
|
||||
sizeof(sensor->ssdb));
|
||||
ret = ipu_bridge_read_acpi_buffer(adev, "SSDB",
|
||||
&sensor->ssdb,
|
||||
sizeof(sensor->ssdb));
|
||||
if (ret)
|
||||
goto err_put_adev;
|
||||
|
||||
snprintf(sensor->name, sizeof(sensor->name), "%s-%u",
|
||||
cfg->hid, sensor->ssdb.link);
|
||||
|
||||
if (sensor->ssdb.vcmtype > ARRAY_SIZE(cio2_vcm_types)) {
|
||||
if (sensor->ssdb.vcmtype > ARRAY_SIZE(ipu_vcm_types)) {
|
||||
dev_warn(&adev->dev, "Unknown VCM type %d\n",
|
||||
sensor->ssdb.vcmtype);
|
||||
sensor->ssdb.vcmtype = 0;
|
||||
@ -330,15 +330,15 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg,
|
||||
goto err_put_adev;
|
||||
}
|
||||
|
||||
if (sensor->ssdb.lanes > CIO2_MAX_LANES) {
|
||||
if (sensor->ssdb.lanes > IPU_MAX_LANES) {
|
||||
dev_err(&adev->dev,
|
||||
"Number of lanes in SSDB is invalid\n");
|
||||
ret = -EINVAL;
|
||||
goto err_free_pld;
|
||||
}
|
||||
|
||||
cio2_bridge_create_fwnode_properties(sensor, bridge, cfg);
|
||||
cio2_bridge_create_connection_swnodes(bridge, sensor);
|
||||
ipu_bridge_create_fwnode_properties(sensor, bridge, cfg);
|
||||
ipu_bridge_create_connection_swnodes(bridge, sensor);
|
||||
|
||||
ret = software_node_register_node_group(sensor->group);
|
||||
if (ret)
|
||||
@ -356,9 +356,9 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg,
|
||||
primary = acpi_fwnode_handle(adev);
|
||||
primary->secondary = fwnode;
|
||||
|
||||
cio2_bridge_instantiate_vcm_i2c_client(sensor);
|
||||
ipu_bridge_instantiate_vcm_i2c_client(sensor);
|
||||
|
||||
dev_info(&cio2->dev, "Found supported sensor %s\n",
|
||||
dev_info(&ipu->dev, "Found supported sensor %s\n",
|
||||
acpi_dev_name(adev));
|
||||
|
||||
bridge->n_sensors++;
|
||||
@ -375,17 +375,17 @@ err_put_adev:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cio2_bridge_connect_sensors(struct cio2_bridge *bridge,
|
||||
struct pci_dev *cio2)
|
||||
static int ipu_bridge_connect_sensors(struct ipu_bridge *bridge,
|
||||
struct pci_dev *ipu)
|
||||
{
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cio2_supported_sensors); i++) {
|
||||
const struct cio2_sensor_config *cfg =
|
||||
&cio2_supported_sensors[i];
|
||||
for (i = 0; i < ARRAY_SIZE(ipu_supported_sensors); i++) {
|
||||
const struct ipu_sensor_config *cfg =
|
||||
&ipu_supported_sensors[i];
|
||||
|
||||
ret = cio2_bridge_connect_sensor(cfg, bridge, cio2);
|
||||
ret = ipu_bridge_connect_sensor(cfg, bridge, ipu);
|
||||
if (ret)
|
||||
goto err_unregister_sensors;
|
||||
}
|
||||
@ -393,7 +393,7 @@ static int cio2_bridge_connect_sensors(struct cio2_bridge *bridge,
|
||||
return 0;
|
||||
|
||||
err_unregister_sensors:
|
||||
cio2_bridge_unregister_sensors(bridge);
|
||||
ipu_bridge_unregister_sensors(bridge);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -409,15 +409,15 @@ err_unregister_sensors:
|
||||
* acpi_dev_ready_for_enumeration() helper, like the i2c-core-acpi code does
|
||||
* for the sensors.
|
||||
*/
|
||||
static int cio2_bridge_sensors_are_ready(void)
|
||||
static int ipu_bridge_sensors_are_ready(void)
|
||||
{
|
||||
struct acpi_device *adev;
|
||||
bool ready = true;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cio2_supported_sensors); i++) {
|
||||
const struct cio2_sensor_config *cfg =
|
||||
&cio2_supported_sensors[i];
|
||||
for (i = 0; i < ARRAY_SIZE(ipu_supported_sensors); i++) {
|
||||
const struct ipu_sensor_config *cfg =
|
||||
&ipu_supported_sensors[i];
|
||||
|
||||
for_each_acpi_dev_match(adev, cfg->hid, NULL, -1) {
|
||||
if (!adev->status.enabled)
|
||||
@ -431,50 +431,50 @@ static int cio2_bridge_sensors_are_ready(void)
|
||||
return ready;
|
||||
}
|
||||
|
||||
int cio2_bridge_init(struct pci_dev *cio2)
|
||||
int ipu_bridge_init(struct pci_dev *ipu)
|
||||
{
|
||||
struct device *dev = &cio2->dev;
|
||||
struct device *dev = &ipu->dev;
|
||||
struct fwnode_handle *fwnode;
|
||||
struct cio2_bridge *bridge;
|
||||
struct ipu_bridge *bridge;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
if (!cio2_bridge_sensors_are_ready())
|
||||
if (!ipu_bridge_sensors_are_ready())
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
|
||||
if (!bridge)
|
||||
return -ENOMEM;
|
||||
|
||||
strscpy(bridge->cio2_node_name, CIO2_HID,
|
||||
sizeof(bridge->cio2_node_name));
|
||||
bridge->cio2_hid_node.name = bridge->cio2_node_name;
|
||||
strscpy(bridge->ipu_node_name, IPU_HID,
|
||||
sizeof(bridge->ipu_node_name));
|
||||
bridge->ipu_hid_node.name = bridge->ipu_node_name;
|
||||
|
||||
ret = software_node_register(&bridge->cio2_hid_node);
|
||||
ret = software_node_register(&bridge->ipu_hid_node);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to register the CIO2 HID node\n");
|
||||
dev_err(dev, "Failed to register the IPU HID node\n");
|
||||
goto err_free_bridge;
|
||||
}
|
||||
|
||||
/*
|
||||
* Map the lane arrangement, which is fixed for the IPU3 (meaning we
|
||||
* only need one, rather than one per sensor). We include it as a
|
||||
* member of the struct cio2_bridge rather than a global variable so
|
||||
* member of the struct ipu_bridge rather than a global variable so
|
||||
* that it survives if the module is unloaded along with the rest of
|
||||
* the struct.
|
||||
*/
|
||||
for (i = 0; i < CIO2_MAX_LANES; i++)
|
||||
for (i = 0; i < IPU_MAX_LANES; i++)
|
||||
bridge->data_lanes[i] = i + 1;
|
||||
|
||||
ret = cio2_bridge_connect_sensors(bridge, cio2);
|
||||
ret = ipu_bridge_connect_sensors(bridge, ipu);
|
||||
if (ret || bridge->n_sensors == 0)
|
||||
goto err_unregister_cio2;
|
||||
goto err_unregister_ipu;
|
||||
|
||||
dev_info(dev, "Connected %d cameras\n", bridge->n_sensors);
|
||||
|
||||
fwnode = software_node_fwnode(&bridge->cio2_hid_node);
|
||||
fwnode = software_node_fwnode(&bridge->ipu_hid_node);
|
||||
if (!fwnode) {
|
||||
dev_err(dev, "Error getting fwnode from cio2 software_node\n");
|
||||
dev_err(dev, "Error getting fwnode from ipu software_node\n");
|
||||
ret = -ENODEV;
|
||||
goto err_unregister_sensors;
|
||||
}
|
||||
@ -484,11 +484,12 @@ int cio2_bridge_init(struct pci_dev *cio2)
|
||||
return 0;
|
||||
|
||||
err_unregister_sensors:
|
||||
cio2_bridge_unregister_sensors(bridge);
|
||||
err_unregister_cio2:
|
||||
software_node_unregister(&bridge->cio2_hid_node);
|
||||
ipu_bridge_unregister_sensors(bridge);
|
||||
err_unregister_ipu:
|
||||
software_node_unregister(&bridge->ipu_hid_node);
|
||||
err_free_bridge:
|
||||
kfree(bridge);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(ipu_bridge_init, INTEL_IPU_BRIDGE);
|
@ -1,25 +1,25 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Author: Dan Scally <djrscally@gmail.com> */
|
||||
#ifndef __CIO2_BRIDGE_H
|
||||
#define __CIO2_BRIDGE_H
|
||||
#ifndef __IPU_BRIDGE_H
|
||||
#define __IPU_BRIDGE_H
|
||||
|
||||
#include <linux/property.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "ipu3-cio2.h"
|
||||
#include "ipu3/ipu3-cio2.h"
|
||||
|
||||
struct i2c_client;
|
||||
|
||||
#define CIO2_HID "INT343E"
|
||||
#define CIO2_MAX_LANES 4
|
||||
#define IPU_HID "INT343E"
|
||||
#define IPU_MAX_LANES 4
|
||||
#define MAX_NUM_LINK_FREQS 3
|
||||
|
||||
/* Values are educated guesses as we don't have a spec */
|
||||
#define CIO2_SENSOR_ROTATION_NORMAL 0
|
||||
#define CIO2_SENSOR_ROTATION_INVERTED 1
|
||||
#define IPU_SENSOR_ROTATION_NORMAL 0
|
||||
#define IPU_SENSOR_ROTATION_INVERTED 1
|
||||
|
||||
#define CIO2_SENSOR_CONFIG(_HID, _NR, ...) \
|
||||
(const struct cio2_sensor_config) { \
|
||||
#define IPU_SENSOR_CONFIG(_HID, _NR, ...) \
|
||||
(const struct ipu_sensor_config) { \
|
||||
.hid = _HID, \
|
||||
.nr_link_freqs = _NR, \
|
||||
.link_freqs = { __VA_ARGS__ } \
|
||||
@ -49,19 +49,19 @@ struct i2c_client;
|
||||
.name = _TYPE, \
|
||||
}
|
||||
|
||||
enum cio2_sensor_swnodes {
|
||||
enum ipu_sensor_swnodes {
|
||||
SWNODE_SENSOR_HID,
|
||||
SWNODE_SENSOR_PORT,
|
||||
SWNODE_SENSOR_ENDPOINT,
|
||||
SWNODE_CIO2_PORT,
|
||||
SWNODE_CIO2_ENDPOINT,
|
||||
SWNODE_IPU_PORT,
|
||||
SWNODE_IPU_ENDPOINT,
|
||||
/* Must be last because it is optional / maybe empty */
|
||||
SWNODE_VCM,
|
||||
SWNODE_COUNT
|
||||
};
|
||||
|
||||
/* Data representation as it is in ACPI SSDB buffer */
|
||||
struct cio2_sensor_ssdb {
|
||||
struct ipu_sensor_ssdb {
|
||||
u8 version;
|
||||
u8 sku;
|
||||
u8 guid_csi2[16];
|
||||
@ -90,7 +90,7 @@ struct cio2_sensor_ssdb {
|
||||
u8 reserved2[13];
|
||||
} __packed;
|
||||
|
||||
struct cio2_property_names {
|
||||
struct ipu_property_names {
|
||||
char clock_frequency[16];
|
||||
char rotation[9];
|
||||
char orientation[12];
|
||||
@ -100,19 +100,19 @@ struct cio2_property_names {
|
||||
char link_frequencies[17];
|
||||
};
|
||||
|
||||
struct cio2_node_names {
|
||||
struct ipu_node_names {
|
||||
char port[7];
|
||||
char endpoint[11];
|
||||
char remote_port[7];
|
||||
};
|
||||
|
||||
struct cio2_sensor_config {
|
||||
struct ipu_sensor_config {
|
||||
const char *hid;
|
||||
const u8 nr_link_freqs;
|
||||
const u64 link_freqs[MAX_NUM_LINK_FREQS];
|
||||
};
|
||||
|
||||
struct cio2_sensor {
|
||||
struct ipu_sensor {
|
||||
/* append ssdb.link(u8) in "-%u" format as suffix of HID */
|
||||
char name[ACPI_ID_LEN + 4];
|
||||
struct acpi_device *adev;
|
||||
@ -121,26 +121,32 @@ struct cio2_sensor {
|
||||
/* SWNODE_COUNT + 1 for terminating NULL */
|
||||
const struct software_node *group[SWNODE_COUNT + 1];
|
||||
struct software_node swnodes[SWNODE_COUNT];
|
||||
struct cio2_node_names node_names;
|
||||
struct ipu_node_names node_names;
|
||||
|
||||
struct cio2_sensor_ssdb ssdb;
|
||||
struct ipu_sensor_ssdb ssdb;
|
||||
struct acpi_pld_info *pld;
|
||||
|
||||
struct cio2_property_names prop_names;
|
||||
struct ipu_property_names prop_names;
|
||||
struct property_entry ep_properties[5];
|
||||
struct property_entry dev_properties[5];
|
||||
struct property_entry cio2_properties[3];
|
||||
struct property_entry ipu_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 {
|
||||
char cio2_node_name[ACPI_ID_LEN];
|
||||
struct software_node cio2_hid_node;
|
||||
struct ipu_bridge {
|
||||
char ipu_node_name[ACPI_ID_LEN];
|
||||
struct software_node ipu_hid_node;
|
||||
u32 data_lanes[4];
|
||||
unsigned int n_sensors;
|
||||
struct cio2_sensor sensors[CIO2_NUM_PORTS];
|
||||
struct ipu_sensor sensors[CIO2_NUM_PORTS];
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPU_BRIDGE)
|
||||
int ipu_bridge_init(struct pci_dev *ipu);
|
||||
#else
|
||||
static inline int ipu_bridge_init(struct pci_dev *ipu) { return 0; }
|
||||
#endif
|
||||
|
||||
#endif
|
@ -17,22 +17,3 @@ config VIDEO_IPU3_CIO2
|
||||
Say Y or M here if you have a Skylake/Kaby Lake SoC with MIPI CSI-2
|
||||
connected camera.
|
||||
The module will be called ipu3-cio2.
|
||||
|
||||
config CIO2_BRIDGE
|
||||
bool "IPU3 CIO2 Sensors Bridge"
|
||||
depends on VIDEO_IPU3_CIO2 && ACPI
|
||||
depends on I2C
|
||||
help
|
||||
This extension provides an API for the ipu3-cio2 driver to create
|
||||
connections to cameras that are hidden in the SSDB buffer in ACPI.
|
||||
It can be used to enable support for cameras in detachable / hybrid
|
||||
devices that ship with Windows.
|
||||
|
||||
Say Y here if your device is a detachable / hybrid laptop that comes
|
||||
with Windows installed by the OEM, for example:
|
||||
|
||||
- Microsoft Surface models (except Surface Pro 3)
|
||||
- The Lenovo Miix line (for example the 510, 520, 710 and 720)
|
||||
- Dell 7285
|
||||
|
||||
If in doubt, say N here.
|
||||
|
@ -2,4 +2,3 @@
|
||||
obj-$(CONFIG_VIDEO_IPU3_CIO2) += ipu3-cio2.o
|
||||
|
||||
ipu3-cio2-y += ipu3-cio2-main.o
|
||||
ipu3-cio2-$(CONFIG_CIO2_BRIDGE) += cio2-bridge.o
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <media/videobuf2-dma-sg.h>
|
||||
|
||||
#include "../ipu-bridge.h"
|
||||
#include "ipu3-cio2.h"
|
||||
|
||||
struct ipu3_cio2_fmt {
|
||||
@ -1724,7 +1725,7 @@ static int cio2_pci_probe(struct pci_dev *pci_dev,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = cio2_bridge_init(pci_dev);
|
||||
r = ipu_bridge_init(pci_dev);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
@ -2057,3 +2058,4 @@ MODULE_AUTHOR("Yuning Pu <yuning.pu@intel.com>");
|
||||
MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("IPU3 CIO2 driver");
|
||||
MODULE_IMPORT_NS(INTEL_IPU_BRIDGE);
|
||||
|
@ -459,10 +459,4 @@ static inline struct cio2_queue *vb2q_to_cio2_queue(struct vb2_queue *vq)
|
||||
return container_of(vq, struct cio2_queue, vbq);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_CIO2_BRIDGE)
|
||||
int cio2_bridge_init(struct pci_dev *cio2);
|
||||
#else
|
||||
static inline int cio2_bridge_init(struct pci_dev *cio2) { return 0; }
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user