Commit 8d28ec7e authored by Hans de Goede's avatar Hans de Goede Committed by Mauro Carvalho Chehab

media: atomisp: Add support for v4l2-async sensor registration

Add support for using v4l2-async sensor registration.

This has been tested with both the gc0310 and the ov2680 sensor drivers.

Drivers must add the ACPI HIDs they match on to the supported_sensors[]
array in the same commit as that they are converted to
v4l2_async_register_subdev_sensor().

Sensor drivers also must check they have a fwnode graph endpoint and return
-EPROBE_DEFER from probe() if there is no endpoint yet. This guarantees
that the GPIO mappings are in place before the driver tries to get GPIOs.

For now it also is still possible to use the old atomisp_gmin_platform
based sensor drivers. This is mainly intended for testing while moving
other sensor drivers over to runtime-pm + v4l2-async.

Link: https://lore.kernel.org/r/20230525190100.130010-2-hdegoede@redhat.comReviewed-by: default avatarAndy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@kernel.org>
parent 5e131b80
......@@ -16,6 +16,7 @@ atomisp-objs += \
pci/atomisp_cmd.o \
pci/atomisp_compat_css20.o \
pci/atomisp_csi2.o \
pci/atomisp_csi2_bridge.o \
pci/atomisp_drvfs.o \
pci/atomisp_fops.o \
pci/atomisp_ioctl.o \
......
......@@ -371,6 +371,10 @@ int atomisp_mipi_csi2_init(struct atomisp_device *isp)
unsigned int i;
int ret;
ret = atomisp_csi2_bridge_init(isp);
if (ret < 0)
return ret;
for (i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++) {
csi2_port = &isp->csi2_port[i];
csi2_port->isp = isp;
......
......@@ -18,17 +18,102 @@
#ifndef __ATOMISP_CSI2_H__
#define __ATOMISP_CSI2_H__
#include <linux/gpio/consumer.h>
#include <linux/property.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-ctrls.h>
#include "../../include/linux/atomisp.h"
#define CSI2_PAD_SINK 0
#define CSI2_PAD_SOURCE 1
#define CSI2_PADS_NUM 2
struct atomisp_device;
#define CSI2_MAX_LANES 4
#define CSI2_MAX_ACPI_GPIOS 2u
struct acpi_device;
struct v4l2_device;
struct atomisp_device;
struct atomisp_sub_device;
struct atomisp_csi2_acpi_gpio_map {
struct acpi_gpio_params params[CSI2_MAX_ACPI_GPIOS];
struct acpi_gpio_mapping mapping[CSI2_MAX_ACPI_GPIOS + 1];
};
struct atomisp_csi2_acpi_gpio_parsing_data {
struct acpi_device *adev;
struct atomisp_csi2_acpi_gpio_map *map;
u32 settings[CSI2_MAX_ACPI_GPIOS];
unsigned int settings_count;
unsigned int res_count;
unsigned int map_count;
};
enum atomisp_csi2_sensor_swnodes {
SWNODE_SENSOR,
SWNODE_SENSOR_PORT,
SWNODE_SENSOR_ENDPOINT,
SWNODE_CSI2_PORT,
SWNODE_CSI2_ENDPOINT,
SWNODE_COUNT
};
struct atomisp_csi2_property_names {
char rotation[9];
char bus_type[9];
char data_lanes[11];
char remote_endpoint[16];
};
struct atomisp_csi2_node_names {
char port[7];
char endpoint[11];
char remote_port[7];
};
struct atomisp_csi2_sensor_config {
const char *hid;
int lanes;
};
struct atomisp_csi2_sensor {
/* Append port in "-%u" format as suffix of HID */
char name[ACPI_ID_LEN + 4];
struct acpi_device *adev;
int port;
int lanes;
/* SWNODE_COUNT + 1 for terminating NULL */
const struct software_node *group[SWNODE_COUNT + 1];
struct software_node swnodes[SWNODE_COUNT];
struct atomisp_csi2_node_names node_names;
struct atomisp_csi2_property_names prop_names;
/* "rotation" + terminating entry */
struct property_entry dev_properties[2];
/* "bus-type", "data-lanes", "remote-endpoint" + terminating entry */
struct property_entry ep_properties[4];
/* "data-lanes", "remote-endpoint" + terminating entry */
struct property_entry csi2_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];
/* GPIO mappings storage */
struct atomisp_csi2_acpi_gpio_map gpio_map;
};
struct atomisp_csi2_bridge {
struct software_node csi2_node;
char csi2_node_name[14];
u32 data_lanes[CSI2_MAX_LANES];
unsigned int n_sensors;
struct atomisp_csi2_sensor sensors[ATOMISP_CAMERA_NR_PORTS];
};
struct atomisp_mipi_csi2_device {
struct v4l2_subdev subdev;
struct media_pad pads[CSI2_PADS_NUM];
......@@ -48,6 +133,8 @@ void atomisp_mipi_csi2_unregister_entities(
struct atomisp_mipi_csi2_device *csi2);
int atomisp_mipi_csi2_register_entities(struct atomisp_mipi_csi2_device *csi2,
struct v4l2_device *vdev);
int atomisp_csi2_bridge_init(struct atomisp_device *isp);
int atomisp_csi2_bridge_parse_firmware(struct atomisp_device *isp);
void atomisp_csi2_configure(struct atomisp_sub_device *asd);
......
This diff is collapsed.
......@@ -27,6 +27,7 @@
#include <linux/idr.h>
#include <media/media-device.h>
#include <media/v4l2-async.h>
#include <media/v4l2-subdev.h>
/* ISP2400*/
......@@ -173,6 +174,7 @@ struct atomisp_device {
struct v4l2_device v4l2_dev;
struct media_device media_dev;
struct atomisp_sub_device asd;
struct v4l2_async_notifier notifier;
struct atomisp_platform_data *pdata;
void *mmu_l1_base;
void __iomem *base;
......
......@@ -27,6 +27,7 @@
#include <linux/dmi.h>
#include <linux/interrupt.h>
#include <linux/bits.h>
#include <media/v4l2-fwnode.h>
#include <asm/iosf_mbi.h>
......@@ -782,7 +783,11 @@ static int atomisp_subdev_probe(struct atomisp_device *isp)
{
const struct atomisp_platform_data *pdata;
struct intel_v4l2_subdev_table *subdevs;
int ret, mipi_port, count;
int ret, mipi_port;
ret = atomisp_csi2_bridge_parse_firmware(isp);
if (ret)
return ret;
pdata = atomisp_get_platform_data();
if (!pdata) {
......@@ -790,23 +795,12 @@ static int atomisp_subdev_probe(struct atomisp_device *isp)
return 0;
}
/* FIXME: should return -EPROBE_DEFER if not all subdevs were probed */
for (count = 0; count < SUBDEV_WAIT_TIMEOUT_MAX_COUNT; count++) {
int camera_count = 0;
for (subdevs = pdata->subdevs; subdevs->type; ++subdevs) {
if (subdevs->type == RAW_CAMERA)
camera_count++;
}
if (camera_count)
break;
msleep(SUBDEV_WAIT_TIMEOUT);
}
/* Wait more time to give more time for subdev init code to finish */
msleep(5 * SUBDEV_WAIT_TIMEOUT);
/* FIXME: should, instead, use I2C probe */
/*
* TODO: this is left here for now to allow testing atomisp-sensor
* drivers which are still using the atomisp_gmin_platform infra before
* converting them to standard v4l2 sensor drivers using runtime-pm +
* ACPI for pm and v4l2_async_register_subdev_sensor() registration.
*/
for (subdevs = pdata->subdevs; subdevs->type; ++subdevs) {
ret = v4l2_device_register_subdev(&isp->v4l2_dev, subdevs->subdev);
if (ret)
......@@ -937,7 +931,7 @@ static int atomisp_register_entities(struct atomisp_device *isp)
return ret;
}
static int atomisp_register_device_nodes(struct atomisp_device *isp)
int atomisp_register_device_nodes(struct atomisp_device *isp)
{
struct atomisp_input_subdev *input;
int i, err;
......@@ -1429,9 +1423,11 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
isp->firmware = NULL;
isp->css_env.isp_css_fw.data = NULL;
err = atomisp_register_device_nodes(isp);
if (err)
err = v4l2_async_nf_register(&isp->v4l2_dev, &isp->notifier);
if (err) {
dev_err(isp->dev, "failed to register async notifier : %d\n", err);
goto css_init_fail;
}
atomisp_drvfs_init(isp);
......
......@@ -30,5 +30,6 @@ int atomisp_video_init(struct atomisp_video_pipe *video);
void atomisp_video_unregister(struct atomisp_video_pipe *video);
const struct firmware *atomisp_load_firmware(struct atomisp_device *isp);
int atomisp_csi_lane_config(struct atomisp_device *isp);
int atomisp_register_device_nodes(struct atomisp_device *isp);
#endif /* __ATOMISP_V4L2_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment