linux-surface/patches/6.7/0012-cameras.patch
Dorian Stoll 852fcb1c2f
Update v6.7 patches
Changes:
 - Add driver for changing the fan profile (Surface Pro 9)
 - Added fixes for IPU3 cameras
 - Reverted DW9719 driver to previous version (Surface Go 2)

Links:
 - kernel: 530f557890
 - fan profile driver: https://github.com/linux-surface/kernel/pull/145
 - camera fixes: https://github.com/linux-surface/kernel/pull/146
2024-03-09 21:08:04 +01:00

1251 lines
40 KiB
Diff

From 5fdcd780891777ef73585adf610593e6e097e6d6 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Sun, 10 Oct 2021 20:56:57 +0200
Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an
INT3472 device
The clk and regulator frameworks expect clk/regulator consumer-devices
to have info about the consumed clks/regulators described in the device's
fw_node.
To work around cases where this info is not present in the firmware tables,
which is often the case on x86/ACPI devices, both frameworks allow the
provider-driver to attach info about consumers to the clks/regulators
when registering these.
This causes problems with the probe ordering wrt drivers for consumers
of these clks/regulators. Since the lookups are only registered when the
provider-driver binds, trying to get these clks/regulators before then
results in a -ENOENT error for clks and a dummy regulator for regulators.
One case where we hit this issue is camera sensors such as e.g. the OV8865
sensor found on the Microsoft Surface Go. The sensor uses clks, regulators
and GPIOs provided by a TPS68470 PMIC which is described in an INT3472
ACPI device. There is special platform code handling this and setting
platform_data with the necessary consumer info on the MFD cells
instantiated for the PMIC under: drivers/platform/x86/intel/int3472.
For this to work properly the ov8865 driver must not bind to the I2C-client
for the OV8865 sensor until after the TPS68470 PMIC gpio, regulator and
clk MFD cells have all been fully setup.
The OV8865 on the Microsoft Surface Go is just one example, all X86
devices using the Intel IPU3 camera block found on recent Intel SoCs
have similar issues where there is an INT3472 HID ACPI-device, which
describes the clks and regulators, and the driver for this INT3472 device
must be fully initialized before the sensor driver (any sensor driver)
binds for things to work properly.
On these devices the ACPI nodes describing the sensors all have a _DEP
dependency on the matching INT3472 ACPI device (there is one per sensor).
This allows solving the probe-ordering problem by delaying the enumeration
(instantiation of the I2C-client in the ov8865 example) of ACPI-devices
which have a _DEP dependency on an INT3472 device.
The new acpi_dev_ready_for_enumeration() helper used for this is also
exported because for devices, which have the enumeration_by_parent flag
set, the parent-driver will do its own scan of child ACPI devices and
it will try to enumerate those during its probe(). Code doing this such
as e.g. the i2c-core-acpi.c code must call this new helper to ensure
that it too delays the enumeration until all the _DEP dependencies are
met on devices which have the new honor_deps flag set.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Patchset: cameras
---
drivers/acpi/scan.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 02bb2cce423f..b123138d3dc0 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -2114,6 +2114,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used,
static void acpi_default_enumeration(struct acpi_device *device)
{
+ if (!acpi_dev_ready_for_enumeration(device))
+ return;
+
/*
* Do not enumerate devices with enumeration_by_parent flag set as
* they will be enumerated by their respective parents.
--
2.44.0
From eb19f5e13f14a8973920d406125f205945558fb9 Mon Sep 17 00:00:00 2001
From: zouxiaoh <xiaohong.zou@intel.com>
Date: Fri, 25 Jun 2021 08:52:59 +0800
Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs
Intel IPU(Image Processing Unit) has its own (IO)MMU hardware,
The IPU driver allocates its own page table that is not mapped
via the DMA, and thus the Intel IOMMU driver blocks access giving
this error: DMAR: DRHD: handling fault status reg 3 DMAR:
[DMA Read] Request device [00:05.0] PASID ffffffff
fault addr 76406000 [fault reason 06] PTE Read access is not set
As IPU is not an external facing device which is not risky, so use
IOMMU passthrough mode for Intel IPUs.
Change-Id: I6dcccdadac308cf42e20a18e1b593381391e3e6b
Depends-On: Iacd67578e8c6a9b9ac73285f52b4081b72fb68a6
Tracked-On: #JIITL8-411
Signed-off-by: Bingbu Cao <bingbu.cao@intel.com>
Signed-off-by: zouxiaoh <xiaohong.zou@intel.com>
Signed-off-by: Xu Chongyang <chongyang.xu@intel.com>
Patchset: cameras
---
drivers/iommu/intel/iommu.c | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index cc6569613255..8a532d32efdd 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -38,6 +38,12 @@
#define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
#define IS_USB_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_SERIAL_USB)
#define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
+#define IS_INTEL_IPU(pdev) ((pdev)->vendor == PCI_VENDOR_ID_INTEL && \
+ ((pdev)->device == 0x9a19 || \
+ (pdev)->device == 0x9a39 || \
+ (pdev)->device == 0x4e19 || \
+ (pdev)->device == 0x465d || \
+ (pdev)->device == 0x1919))
#define IS_IPTS(pdev) ((pdev)->vendor == PCI_VENDOR_ID_INTEL && \
((pdev)->device == 0x9d3e))
#define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e)
@@ -294,12 +300,14 @@ EXPORT_SYMBOL_GPL(intel_iommu_enabled);
static int dmar_map_gfx = 1;
static int dmar_map_ipts = 1;
+static int dmar_map_ipu = 1;
static int intel_iommu_superpage = 1;
static int iommu_identity_mapping;
static int iommu_skip_te_disable;
#define IDENTMAP_GFX 2
#define IDENTMAP_AZALIA 4
+#define IDENTMAP_IPU 8
#define IDENTMAP_IPTS 16
const struct iommu_ops intel_iommu_ops;
@@ -2553,6 +2561,9 @@ static int device_def_domain_type(struct device *dev)
if ((iommu_identity_mapping & IDENTMAP_GFX) && IS_GFX_DEVICE(pdev))
return IOMMU_DOMAIN_IDENTITY;
+ if ((iommu_identity_mapping & IDENTMAP_IPU) && IS_INTEL_IPU(pdev))
+ return IOMMU_DOMAIN_IDENTITY;
+
if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev))
return IOMMU_DOMAIN_IDENTITY;
}
@@ -2862,6 +2873,9 @@ static int __init init_dmars(void)
if (!dmar_map_gfx)
iommu_identity_mapping |= IDENTMAP_GFX;
+ if (!dmar_map_ipu)
+ iommu_identity_mapping |= IDENTMAP_IPU;
+
if (!dmar_map_ipts)
iommu_identity_mapping |= IDENTMAP_IPTS;
@@ -4987,6 +5001,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev)
dmar_map_gfx = 0;
}
+static void quirk_iommu_ipu(struct pci_dev *dev)
+{
+ if (!IS_INTEL_IPU(dev))
+ return;
+
+ if (risky_device(dev))
+ return;
+
+ pci_info(dev, "Passthrough IOMMU for integrated Intel IPU\n");
+ dmar_map_ipu = 0;
+}
+
static void quirk_iommu_ipts(struct pci_dev *dev)
{
if (!IS_IPTS(dev))
@@ -4998,6 +5024,7 @@ static void quirk_iommu_ipts(struct pci_dev *dev)
pci_info(dev, "Passthrough IOMMU for IPTS\n");
dmar_map_ipts = 0;
}
+
/* G4x/GM45 integrated gfx dmar support is totally busted. */
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx);
@@ -5033,6 +5060,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx);
+/* disable IPU dmar support */
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_iommu_ipu);
+
/* disable IPTS dmar support */
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts);
--
2.44.0
From 1b16e7cbcbf699e4d841424568e0de1cee048d93 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Sun, 10 Oct 2021 20:57:02 +0200
Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain
The TPS68470 PMIC has an I2C passthrough mode through which I2C traffic
can be forwarded to a device connected to the PMIC as though it were
connected directly to the system bus. Enable this mode when the chip
is initialised.
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/platform/x86/intel/int3472/tps68470.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c
index 1e107fd49f82..e3e1696e7f0e 100644
--- a/drivers/platform/x86/intel/int3472/tps68470.c
+++ b/drivers/platform/x86/intel/int3472/tps68470.c
@@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap)
return ret;
}
+ /* Enable I2C daisy chain */
+ ret = regmap_write(regmap, TPS68470_REG_S_I2C_CTL, 0x03);
+ if (ret) {
+ dev_err(dev, "Failed to enable i2c daisy chain\n");
+ return ret;
+ }
+
dev_info(dev, "TPS68470 REVID: 0x%02x\n", version);
return 0;
--
2.44.0
From a856e6ec1aa1ce0e88abdd423a151f2bbddb8134 Mon Sep 17 00:00:00 2001
From: Daniel Scally <dan.scally@ideasonboard.com>
Date: Thu, 2 Mar 2023 12:59:39 +0000
Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E
ACPI _HID INT347E represents the OmniVision 7251 camera sensor. The
driver for this sensor expects a single pin named "enable", but on
some Microsoft Surface platforms the sensor is assigned a single
GPIO who's type flag is INT3472_GPIO_TYPE_RESET.
Remap the GPIO pin's function from "reset" to "enable". This is done
outside of the existing remap table since it is a more widespread
discrepancy than that method is designed for. Additionally swap the
polarity of the pin to match the driver's expectation.
Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com>
Patchset: cameras
---
drivers/platform/x86/intel/int3472/discrete.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c
index 07b302e09340..1d3097bc7e48 100644
--- a/drivers/platform/x86/intel/int3472/discrete.c
+++ b/drivers/platform/x86/intel/int3472/discrete.c
@@ -83,12 +83,26 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347
const char *func, u32 polarity)
{
int ret;
+ const struct acpi_device_id ov7251_ids[] = {
+ { "INT347E" },
+ };
if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) {
dev_warn(int3472->dev, "Too many GPIOs mapped\n");
return -EINVAL;
}
+ /*
+ * In addition to the function remap table we need to bulk remap the
+ * "reset" GPIO for the OmniVision 7251 sensor, as the driver for that
+ * expects its only GPIO pin to be called "enable" (and to have the
+ * opposite polarity).
+ */
+ if (!strcmp(func, "reset") && !acpi_match_device_ids(int3472->sensor, ov7251_ids)) {
+ func = "enable";
+ polarity = GPIO_ACTIVE_HIGH;
+ }
+
ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios],
agpio, func, polarity);
if (ret)
--
2.44.0
From a7a10c4493fe0a381f12fd6a20a024e7797bd37c Mon Sep 17 00:00:00 2001
From: Daniel Scally <dan.scally@ideasonboard.com>
Date: Tue, 21 Mar 2023 13:45:26 +0000
Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251
Update the control ID for the gain control in the ov7251 driver to
V4L2_CID_ANALOGUE_GAIN.
Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com>
Patchset: cameras
---
drivers/media/i2c/ov7251.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c
index 6582cc0e2384..fd0796b6e07e 100644
--- a/drivers/media/i2c/ov7251.c
+++ b/drivers/media/i2c/ov7251.c
@@ -1051,7 +1051,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_EXPOSURE:
ret = ov7251_set_exposure(ov7251, ctrl->val);
break;
- case V4L2_CID_GAIN:
+ case V4L2_CID_ANALOGUE_GAIN:
ret = ov7251_set_gain(ov7251, ctrl->val);
break;
case V4L2_CID_TEST_PATTERN:
@@ -1553,7 +1553,7 @@ static int ov7251_init_ctrls(struct ov7251 *ov7251)
ov7251->exposure = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops,
V4L2_CID_EXPOSURE, 1, 32, 1, 32);
ov7251->gain = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops,
- V4L2_CID_GAIN, 16, 1023, 1, 16);
+ V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 16);
v4l2_ctrl_new_std_menu_items(&ov7251->ctrls, &ov7251_ctrl_ops,
V4L2_CID_TEST_PATTERN,
ARRAY_SIZE(ov7251_test_pattern_menu) - 1,
--
2.44.0
From e96fa67c9172fac9aa6e68199cf7e29d074c21e6 Mon Sep 17 00:00:00 2001
From: Daniel Scally <dan.scally@ideasonboard.com>
Date: Wed, 22 Mar 2023 11:01:42 +0000
Subject: [PATCH] media: v4l2-core: Acquire privacy led in
v4l2_async_register_subdev()
The current call to v4l2_subdev_get_privacy_led() is contained in
v4l2_async_register_subdev_sensor(), but that function isn't used by
all the sensor drivers. Move the acquisition of the privacy led to
v4l2_async_register_subdev() instead.
Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com>
Patchset: cameras
---
drivers/media/v4l2-core/v4l2-async.c | 4 ++++
drivers/media/v4l2-core/v4l2-fwnode.c | 4 ----
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 8cfd593d293d..c32f0d1b29d4 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -796,6 +796,10 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
INIT_LIST_HEAD(&sd->asc_list);
+ ret = v4l2_subdev_get_privacy_led(sd);
+ if (ret < 0)
+ return ret;
+
/*
* No reference taken. The reference is held by the device (struct
* v4l2_subdev.dev), and async sub-device does not exist independently
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index 7f181fbbb140..1c0347de4e21 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -1217,10 +1217,6 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd)
v4l2_async_subdev_nf_init(notifier, sd);
- ret = v4l2_subdev_get_privacy_led(sd);
- if (ret < 0)
- goto out_cleanup;
-
ret = v4l2_async_nf_parse_fwnode_sensor(sd->dev, notifier);
if (ret < 0)
goto out_cleanup;
--
2.44.0
From 68dac72bec1c99890d35d6bfd1b1f66e0cf8789c Mon Sep 17 00:00:00 2001
From: Kate Hsuan <hpa@redhat.com>
Date: Tue, 21 Mar 2023 23:37:16 +0800
Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED
Add MFD cell for tps68470-led.
Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com>
Signed-off-by: Kate Hsuan <hpa@redhat.com>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Patchset: cameras
---
drivers/platform/x86/intel/int3472/tps68470.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c
index e3e1696e7f0e..423dc555093f 100644
--- a/drivers/platform/x86/intel/int3472/tps68470.c
+++ b/drivers/platform/x86/intel/int3472/tps68470.c
@@ -17,7 +17,7 @@
#define DESIGNED_FOR_CHROMEOS 1
#define DESIGNED_FOR_WINDOWS 2
-#define TPS68470_WIN_MFD_CELL_COUNT 3
+#define TPS68470_WIN_MFD_CELL_COUNT 4
static const struct mfd_cell tps68470_cros[] = {
{ .name = "tps68470-gpio" },
@@ -200,7 +200,8 @@ static int skl_int3472_tps68470_probe(struct i2c_client *client)
cells[1].name = "tps68470-regulator";
cells[1].platform_data = (void *)board_data->tps68470_regulator_pdata;
cells[1].pdata_size = sizeof(struct tps68470_regulator_platform_data);
- cells[2].name = "tps68470-gpio";
+ cells[2].name = "tps68470-led";
+ cells[3].name = "tps68470-gpio";
for (i = 0; i < board_data->n_gpiod_lookups; i++)
gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]);
--
2.44.0
From 3f446f24aecaba808693f0173e28972e651fa87d Mon Sep 17 00:00:00 2001
From: Kate Hsuan <hpa@redhat.com>
Date: Tue, 21 Mar 2023 23:37:17 +0800
Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB
Add flags for both LEDA(TPS68470_ILEDCTL_ENA), LEDB
(TPS68470_ILEDCTL_ENB), and current control mask for LEDB
(TPS68470_ILEDCTL_CTRLB)
Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Kate Hsuan <hpa@redhat.com>
Patchset: cameras
---
include/linux/mfd/tps68470.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h
index 7807fa329db0..2d2abb25b944 100644
--- a/include/linux/mfd/tps68470.h
+++ b/include/linux/mfd/tps68470.h
@@ -34,6 +34,7 @@
#define TPS68470_REG_SGPO 0x22
#define TPS68470_REG_GPDI 0x26
#define TPS68470_REG_GPDO 0x27
+#define TPS68470_REG_ILEDCTL 0x28
#define TPS68470_REG_VCMVAL 0x3C
#define TPS68470_REG_VAUX1VAL 0x3D
#define TPS68470_REG_VAUX2VAL 0x3E
@@ -94,4 +95,8 @@
#define TPS68470_GPIO_MODE_OUT_CMOS 2
#define TPS68470_GPIO_MODE_OUT_ODRAIN 3
+#define TPS68470_ILEDCTL_ENA BIT(2)
+#define TPS68470_ILEDCTL_ENB BIT(6)
+#define TPS68470_ILEDCTL_CTRLB GENMASK(5, 4)
+
#endif /* __LINUX_MFD_TPS68470_H */
--
2.44.0
From a0fe4ec438c5edb9f4360c8a2a5f5269d05c44ef Mon Sep 17 00:00:00 2001
From: Kate Hsuan <hpa@redhat.com>
Date: Tue, 21 Mar 2023 23:37:18 +0800
Subject: [PATCH] leds: tps68470: Add LED control for tps68470
There are two LED controllers, LEDA indicator LED and LEDB flash LED for
tps68470. LEDA can be enabled by setting TPS68470_ILEDCTL_ENA. Moreover,
tps68470 provides four levels of power status for LEDB. If the
properties called "ti,ledb-current" can be found, the current will be
set according to the property values. These two LEDs can be controlled
through the LED class of sysfs (tps68470-leda and tps68470-ledb).
Signed-off-by: Kate Hsuan <hpa@redhat.com>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Patchset: cameras
---
drivers/leds/Kconfig | 12 +++
drivers/leds/Makefile | 1 +
drivers/leds/leds-tps68470.c | 185 +++++++++++++++++++++++++++++++++++
3 files changed, 198 insertions(+)
create mode 100644 drivers/leds/leds-tps68470.c
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index a3a9ac5b5338..0bc6845b5d29 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -875,6 +875,18 @@ config LEDS_TPS6105X
It is a single boost converter primarily for white LEDs and
audio amplifiers.
+config LEDS_TPS68470
+ tristate "LED support for TI TPS68470"
+ depends on LEDS_CLASS
+ depends on INTEL_SKL_INT3472
+ help
+ This driver supports TPS68470 PMIC with LED chip.
+ It provides two LED controllers, with the ability to drive 2
+ indicator LEDs and 2 flash LEDs.
+
+ To compile this driver as a module, choose M and it will be
+ called leds-tps68470
+
config LEDS_IP30
tristate "LED support for SGI Octane machines"
depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index d7348e8bc019..10caea4e7c61 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -84,6 +84,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o
obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o
obj-$(CONFIG_LEDS_TLC591XX) += leds-tlc591xx.o
obj-$(CONFIG_LEDS_TPS6105X) += leds-tps6105x.o
+obj-$(CONFIG_LEDS_TPS68470) += leds-tps68470.o
obj-$(CONFIG_LEDS_TURRIS_OMNIA) += leds-turris-omnia.o
obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o
obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o
diff --git a/drivers/leds/leds-tps68470.c b/drivers/leds/leds-tps68470.c
new file mode 100644
index 000000000000..35aeb5db89c8
--- /dev/null
+++ b/drivers/leds/leds-tps68470.c
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * LED driver for TPS68470 PMIC
+ *
+ * Copyright (C) 2023 Red Hat
+ *
+ * Authors:
+ * Kate Hsuan <hpa@redhat.com>
+ */
+
+#include <linux/leds.h>
+#include <linux/mfd/tps68470.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+
+
+#define lcdev_to_led(led_cdev) \
+ container_of(led_cdev, struct tps68470_led, lcdev)
+
+#define led_to_tps68470(led, index) \
+ container_of(led, struct tps68470_device, leds[index])
+
+enum tps68470_led_ids {
+ TPS68470_ILED_A,
+ TPS68470_ILED_B,
+ TPS68470_NUM_LEDS
+};
+
+static const char *tps68470_led_names[] = {
+ [TPS68470_ILED_A] = "tps68470-iled_a",
+ [TPS68470_ILED_B] = "tps68470-iled_b",
+};
+
+struct tps68470_led {
+ unsigned int led_id;
+ struct led_classdev lcdev;
+};
+
+struct tps68470_device {
+ struct device *dev;
+ struct regmap *regmap;
+ struct tps68470_led leds[TPS68470_NUM_LEDS];
+};
+
+enum ctrlb_current {
+ CTRLB_2MA = 0,
+ CTRLB_4MA = 1,
+ CTRLB_8MA = 2,
+ CTRLB_16MA = 3,
+};
+
+static int tps68470_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness)
+{
+ struct tps68470_led *led = lcdev_to_led(led_cdev);
+ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id);
+ struct regmap *regmap = tps68470->regmap;
+
+ switch (led->led_id) {
+ case TPS68470_ILED_A:
+ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENA,
+ brightness ? TPS68470_ILEDCTL_ENA : 0);
+ case TPS68470_ILED_B:
+ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENB,
+ brightness ? TPS68470_ILEDCTL_ENB : 0);
+ }
+ return -EINVAL;
+}
+
+static enum led_brightness tps68470_brightness_get(struct led_classdev *led_cdev)
+{
+ struct tps68470_led *led = lcdev_to_led(led_cdev);
+ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id);
+ struct regmap *regmap = tps68470->regmap;
+ int ret = 0;
+ int value = 0;
+
+ ret = regmap_read(regmap, TPS68470_REG_ILEDCTL, &value);
+ if (ret)
+ return dev_err_probe(led_cdev->dev, -EINVAL, "failed on reading register\n");
+
+ switch (led->led_id) {
+ case TPS68470_ILED_A:
+ value = value & TPS68470_ILEDCTL_ENA;
+ break;
+ case TPS68470_ILED_B:
+ value = value & TPS68470_ILEDCTL_ENB;
+ break;
+ }
+
+ return value ? LED_ON : LED_OFF;
+}
+
+
+static int tps68470_ledb_current_init(struct platform_device *pdev,
+ struct tps68470_device *tps68470)
+{
+ int ret = 0;
+ unsigned int curr;
+
+ /* configure LEDB current if the properties can be got */
+ if (!device_property_read_u32(&pdev->dev, "ti,ledb-current", &curr)) {
+ if (curr > CTRLB_16MA) {
+ dev_err(&pdev->dev,
+ "Invalid LEDB current value: %d\n",
+ curr);
+ return -EINVAL;
+ }
+ ret = regmap_update_bits(tps68470->regmap, TPS68470_REG_ILEDCTL,
+ TPS68470_ILEDCTL_CTRLB, curr);
+ }
+ return ret;
+}
+
+static int tps68470_leds_probe(struct platform_device *pdev)
+{
+ int i = 0;
+ int ret = 0;
+ struct tps68470_device *tps68470;
+ struct tps68470_led *led;
+ struct led_classdev *lcdev;
+
+ tps68470 = devm_kzalloc(&pdev->dev, sizeof(struct tps68470_device),
+ GFP_KERNEL);
+ if (!tps68470)
+ return -ENOMEM;
+
+ tps68470->dev = &pdev->dev;
+ tps68470->regmap = dev_get_drvdata(pdev->dev.parent);
+
+ for (i = 0; i < TPS68470_NUM_LEDS; i++) {
+ led = &tps68470->leds[i];
+ lcdev = &led->lcdev;
+
+ led->led_id = i;
+
+ lcdev->name = devm_kasprintf(tps68470->dev, GFP_KERNEL, "%s::%s",
+ tps68470_led_names[i], LED_FUNCTION_INDICATOR);
+ if (!lcdev->name)
+ return -ENOMEM;
+
+ lcdev->max_brightness = 1;
+ lcdev->brightness = 0;
+ lcdev->brightness_set_blocking = tps68470_brightness_set;
+ lcdev->brightness_get = tps68470_brightness_get;
+ lcdev->dev = &pdev->dev;
+
+ ret = devm_led_classdev_register(tps68470->dev, lcdev);
+ if (ret) {
+ dev_err_probe(tps68470->dev, ret,
+ "error registering led\n");
+ goto err_exit;
+ }
+
+ if (i == TPS68470_ILED_B) {
+ ret = tps68470_ledb_current_init(pdev, tps68470);
+ if (ret)
+ goto err_exit;
+ }
+ }
+
+err_exit:
+ if (ret) {
+ for (i = 0; i < TPS68470_NUM_LEDS; i++) {
+ if (tps68470->leds[i].lcdev.name)
+ devm_led_classdev_unregister(&pdev->dev,
+ &tps68470->leds[i].lcdev);
+ }
+ }
+
+ return ret;
+}
+static struct platform_driver tps68470_led_driver = {
+ .driver = {
+ .name = "tps68470-led",
+ },
+ .probe = tps68470_leds_probe,
+};
+
+module_platform_driver(tps68470_led_driver);
+
+MODULE_ALIAS("platform:tps68470-led");
+MODULE_DESCRIPTION("LED driver for TPS68470 PMIC");
+MODULE_LICENSE("GPL v2");
--
2.44.0
From 16cc6c6241fb32dcb09bae700dba0b2dc7b6c0df Mon Sep 17 00:00:00 2001
From: Hidenori Kobayashi <hidenorik@chromium.org>
Date: Tue, 9 Jan 2024 17:09:09 +0900
Subject: [PATCH] media: staging: ipu3-imgu: Set fields before
media_entity_pads_init()
The imgu driver fails to probe with the following message because it
does not set the pad's flags before calling media_entity_pads_init().
[ 14.596315] ipu3-imgu 0000:00:05.0: failed initialize subdev media entity (-22)
[ 14.596322] ipu3-imgu 0000:00:05.0: failed to register subdev0 ret (-22)
[ 14.596327] ipu3-imgu 0000:00:05.0: failed to register pipes (-22)
[ 14.596331] ipu3-imgu 0000:00:05.0: failed to create V4L2 devices (-22)
Fix the initialization order so that the driver probe succeeds. The ops
initialization is also moved together for readability.
Fixes: a0ca1627b450 ("media: staging/intel-ipu3: Add v4l2 driver based on media framework")
Cc: <stable@vger.kernel.org> # 6.7
Cc: Dan Carpenter <dan.carpenter@linaro.org>
Signed-off-by: Hidenori Kobayashi <hidenorik@chromium.org>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
---
drivers/staging/media/ipu3/ipu3-v4l2.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c
index e530767e80a5..55cc44a401bc 100644
--- a/drivers/staging/media/ipu3/ipu3-v4l2.c
+++ b/drivers/staging/media/ipu3/ipu3-v4l2.c
@@ -1069,6 +1069,11 @@ static int imgu_v4l2_subdev_register(struct imgu_device *imgu,
struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
/* Initialize subdev media entity */
+ imgu_sd->subdev.entity.ops = &imgu_media_ops;
+ for (i = 0; i < IMGU_NODE_NUM; i++) {
+ imgu_sd->subdev_pads[i].flags = imgu_pipe->nodes[i].output ?
+ MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
+ }
r = media_entity_pads_init(&imgu_sd->subdev.entity, IMGU_NODE_NUM,
imgu_sd->subdev_pads);
if (r) {
@@ -1076,11 +1081,6 @@ static int imgu_v4l2_subdev_register(struct imgu_device *imgu,
"failed initialize subdev media entity (%d)\n", r);
return r;
}
- imgu_sd->subdev.entity.ops = &imgu_media_ops;
- for (i = 0; i < IMGU_NODE_NUM; i++) {
- imgu_sd->subdev_pads[i].flags = imgu_pipe->nodes[i].output ?
- MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
- }
/* Initialize subdev */
v4l2_subdev_init(&imgu_sd->subdev, &imgu_subdev_ops);
@@ -1177,15 +1177,15 @@ static int imgu_v4l2_node_setup(struct imgu_device *imgu, unsigned int pipe,
}
/* Initialize media entities */
+ node->vdev_pad.flags = node->output ?
+ MEDIA_PAD_FL_SOURCE : MEDIA_PAD_FL_SINK;
+ vdev->entity.ops = NULL;
r = media_entity_pads_init(&vdev->entity, 1, &node->vdev_pad);
if (r) {
dev_err(dev, "failed initialize media entity (%d)\n", r);
mutex_destroy(&node->lock);
return r;
}
- node->vdev_pad.flags = node->output ?
- MEDIA_PAD_FL_SOURCE : MEDIA_PAD_FL_SINK;
- vdev->entity.ops = NULL;
/* Initialize vbq */
vbq->type = node->vdev_fmt.type;
--
2.44.0
From 2c1c03f035d43f5642f2985980cb4700ac9b7912 Mon Sep 17 00:00:00 2001
From: Sakari Ailus <sakari.ailus@linux.intel.com>
Date: Thu, 25 May 2023 14:12:04 +0300
Subject: [PATCH] media: ipu3-cio2: Further clean up async subdev link creation
Use v4l2_create_fwnode_links_to_pad() to create links from async
sub-devices to the CSI-2 receiver subdevs.
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
---
drivers/media/pci/intel/ipu3/ipu3-cio2.c | 22 +++++-----------------
1 file changed, 5 insertions(+), 17 deletions(-)
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
index 5dd69a251b6a..c6c31215967b 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
@@ -28,6 +28,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-event.h>
#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mc.h>
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-dma-sg.h>
@@ -1421,7 +1422,6 @@ static void cio2_notifier_unbind(struct v4l2_async_notifier *notifier,
static int cio2_notifier_complete(struct v4l2_async_notifier *notifier)
{
struct cio2_device *cio2 = to_cio2_device(notifier);
- struct device *dev = &cio2->pci_dev->dev;
struct sensor_async_subdev *s_asd;
struct v4l2_async_connection *asd;
struct cio2_queue *q;
@@ -1431,23 +1431,10 @@ static int cio2_notifier_complete(struct v4l2_async_notifier *notifier)
s_asd = to_sensor_asd(asd);
q = &cio2->queue[s_asd->csi2.port];
- ret = media_entity_get_fwnode_pad(&q->sensor->entity,
- s_asd->asd.match.fwnode,
- MEDIA_PAD_FL_SOURCE);
- if (ret < 0) {
- dev_err(dev, "no pad for endpoint %pfw (%d)\n",
- s_asd->asd.match.fwnode, ret);
- return ret;
- }
-
- ret = media_create_pad_link(&q->sensor->entity, ret,
- &q->subdev.entity, CIO2_PAD_SINK,
- 0);
- if (ret) {
- dev_err(dev, "failed to create link for %s (endpoint %pfw, error %d)\n",
- q->sensor->name, s_asd->asd.match.fwnode, ret);
+ ret = v4l2_create_fwnode_links_to_pad(asd->sd,
+ &q->subdev_pads[CIO2_PAD_SINK], 0);
+ if (ret)
return ret;
- }
}
return v4l2_device_register_subdev_nodes(&cio2->v4l2_dev);
@@ -1586,6 +1573,7 @@ static int cio2_queue_init(struct cio2_device *cio2, struct cio2_queue *q)
v4l2_subdev_init(subdev, &cio2_subdev_ops);
subdev->flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
subdev->owner = THIS_MODULE;
+ subdev->dev = dev;
snprintf(subdev->name, sizeof(subdev->name),
CIO2_ENTITY_NAME " %td", q - cio2->queue);
subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
--
2.44.0
From f4f07d5f5560318a32311d135ac0463ad81d44c1 Mon Sep 17 00:00:00 2001
From: mojyack <mojyack@gmail.com>
Date: Sat, 3 Feb 2024 12:53:33 +0900
Subject: [PATCH] media: i2c: Revert DW9719 driver
---
drivers/media/i2c/dw9719.c | 199 +++++++++++++++++++++++++------------
1 file changed, 137 insertions(+), 62 deletions(-)
diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c
index c626ed845928..d5f585dabb60 100644
--- a/drivers/media/i2c/dw9719.c
+++ b/drivers/media/i2c/dw9719.c
@@ -6,13 +6,14 @@
* https://github.com/ZenfoneArea/android_kernel_asus_zenfone5
*/
+#include <asm/unaligned.h>
+
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/types.h>
-#include <media/v4l2-cci.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
@@ -20,31 +21,29 @@
#define DW9719_MAX_FOCUS_POS 1023
#define DW9719_CTRL_STEPS 16
#define DW9719_CTRL_DELAY_US 1000
+#define DELAY_MAX_PER_STEP_NS (1000000 * 1023)
-#define DW9719_INFO CCI_REG8(0)
+#define DW9719_INFO 0
#define DW9719_ID 0xF1
+#define DW9719_CONTROL 2
+#define DW9719_VCM_CURRENT 3
-#define DW9719_CONTROL CCI_REG8(2)
-#define DW9719_ENABLE_RINGING 0x02
-
-#define DW9719_VCM_CURRENT CCI_REG16(3)
-
-#define DW9719_MODE CCI_REG8(6)
-#define DW9719_MODE_SAC_SHIFT 4
-#define DW9719_MODE_SAC3 4
+#define DW9719_MODE 6
+#define DW9719_VCM_FREQ 7
-#define DW9719_VCM_FREQ CCI_REG8(7)
+#define DW9719_MODE_SAC3 0x40
#define DW9719_DEFAULT_VCM_FREQ 0x60
+#define DW9719_ENABLE_RINGING 0x02
+
+#define NUM_REGULATORS 2
#define to_dw9719_device(x) container_of(x, struct dw9719_device, sd)
struct dw9719_device {
- struct v4l2_subdev sd;
struct device *dev;
- struct regmap *regmap;
- struct regulator *regulator;
- u32 sac_mode;
- u32 vcm_freq;
+ struct i2c_client *client;
+ struct regulator_bulk_data regulators[NUM_REGULATORS];
+ struct v4l2_subdev sd;
struct dw9719_v4l2_ctrls {
struct v4l2_ctrl_handler handler;
@@ -52,18 +51,79 @@ struct dw9719_device {
} ctrls;
};
+static int dw9719_i2c_rd8(struct i2c_client *client, u8 reg, u8 *val)
+{
+ struct i2c_msg msg[2];
+ u8 buf[2] = { reg };
+ int ret;
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 1;
+ msg[0].buf = buf;
+
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = 1;
+ msg[1].buf = &buf[1];
+ *val = 0;
+
+ ret = i2c_transfer(client->adapter, msg, 2);
+ if (ret < 0)
+ return ret;
+
+ *val = buf[1];
+
+ return 0;
+}
+
+static int dw9719_i2c_wr8(struct i2c_client *client, u8 reg, u8 val)
+{
+ struct i2c_msg msg;
+ int ret;
+
+ u8 buf[2] = { reg, val };
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.len = sizeof(buf);
+ msg.buf = buf;
+
+ ret = i2c_transfer(client->adapter, &msg, 1);
+
+ return ret < 0 ? ret : 0;
+}
+
+static int dw9719_i2c_wr16(struct i2c_client *client, u8 reg, u16 val)
+{
+ struct i2c_msg msg;
+ u8 buf[3] = { reg };
+ int ret;
+
+ put_unaligned_be16(val, buf + 1);
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.len = sizeof(buf);
+ msg.buf = buf;
+
+ ret = i2c_transfer(client->adapter, &msg, 1);
+
+ return ret < 0 ? ret : 0;
+}
+
static int dw9719_detect(struct dw9719_device *dw9719)
{
int ret;
- u64 val;
+ u8 val;
- ret = cci_read(dw9719->regmap, DW9719_INFO, &val, NULL);
+ ret = dw9719_i2c_rd8(dw9719->client, DW9719_INFO, &val);
if (ret < 0)
return ret;
if (val != DW9719_ID) {
dev_err(dw9719->dev, "Failed to detect correct id\n");
- return -ENXIO;
+ ret = -ENXIO;
}
return 0;
@@ -71,37 +131,54 @@ static int dw9719_detect(struct dw9719_device *dw9719)
static int dw9719_power_down(struct dw9719_device *dw9719)
{
- return regulator_disable(dw9719->regulator);
+ return regulator_bulk_disable(NUM_REGULATORS, dw9719->regulators);
}
static int dw9719_power_up(struct dw9719_device *dw9719)
{
int ret;
- ret = regulator_enable(dw9719->regulator);
+ ret = regulator_bulk_enable(NUM_REGULATORS, dw9719->regulators);
if (ret)
return ret;
/* Jiggle SCL pin to wake up device */
- cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret);
+ ret = dw9719_i2c_wr8(dw9719->client, DW9719_CONTROL, 1);
- /* Need 100us to transit from SHUTDOWN to STANDBY */
- fsleep(100);
+ /* Need 100us to transit from SHUTDOWN to STANDBY*/
+ usleep_range(100, 1000);
- cci_write(dw9719->regmap, DW9719_CONTROL, DW9719_ENABLE_RINGING, &ret);
- cci_write(dw9719->regmap, DW9719_MODE,
- dw9719->sac_mode << DW9719_MODE_SAC_SHIFT, &ret);
- cci_write(dw9719->regmap, DW9719_VCM_FREQ, dw9719->vcm_freq, &ret);
+ ret = dw9719_i2c_wr8(dw9719->client, DW9719_CONTROL,
+ DW9719_ENABLE_RINGING);
+ if (ret < 0)
+ goto fail_powerdown;
- if (ret)
- dw9719_power_down(dw9719);
+ ret = dw9719_i2c_wr8(dw9719->client, DW9719_MODE, DW9719_MODE_SAC3);
+ if (ret < 0)
+ goto fail_powerdown;
+
+ ret = dw9719_i2c_wr8(dw9719->client, DW9719_VCM_FREQ,
+ DW9719_DEFAULT_VCM_FREQ);
+ if (ret < 0)
+ goto fail_powerdown;
+
+ return 0;
+fail_powerdown:
+ dw9719_power_down(dw9719);
return ret;
}
static int dw9719_t_focus_abs(struct dw9719_device *dw9719, s32 value)
{
- return cci_write(dw9719->regmap, DW9719_VCM_CURRENT, value, NULL);
+ int ret;
+
+ value = clamp(value, 0, DW9719_MAX_FOCUS_POS);
+ ret = dw9719_i2c_wr16(dw9719->client, DW9719_VCM_CURRENT, value);
+ if (ret < 0)
+ return ret;
+
+ return 0;
}
static int dw9719_set_ctrl(struct v4l2_ctrl *ctrl)
@@ -132,7 +209,7 @@ static const struct v4l2_ctrl_ops dw9719_ctrl_ops = {
.s_ctrl = dw9719_set_ctrl,
};
-static int dw9719_suspend(struct device *dev)
+static int __maybe_unused dw9719_suspend(struct device *dev)
{
struct v4l2_subdev *sd = dev_get_drvdata(dev);
struct dw9719_device *dw9719 = to_dw9719_device(sd);
@@ -151,7 +228,7 @@ static int dw9719_suspend(struct device *dev)
return dw9719_power_down(dw9719);
}
-static int dw9719_resume(struct device *dev)
+static int __maybe_unused dw9719_resume(struct device *dev)
{
struct v4l2_subdev *sd = dev_get_drvdata(dev);
struct dw9719_device *dw9719 = to_dw9719_device(sd);
@@ -201,7 +278,9 @@ static int dw9719_init_controls(struct dw9719_device *dw9719)
const struct v4l2_ctrl_ops *ops = &dw9719_ctrl_ops;
int ret;
- v4l2_ctrl_handler_init(&dw9719->ctrls.handler, 1);
+ ret = v4l2_ctrl_handler_init(&dw9719->ctrls.handler, 1);
+ if (ret)
+ return ret;
dw9719->ctrls.focus = v4l2_ctrl_new_std(&dw9719->ctrls.handler, ops,
V4L2_CID_FOCUS_ABSOLUTE, 0,
@@ -214,7 +293,8 @@ static int dw9719_init_controls(struct dw9719_device *dw9719)
}
dw9719->sd.ctrl_handler = &dw9719->ctrls.handler;
- return 0;
+
+ return ret;
err_free_handler:
v4l2_ctrl_handler_free(&dw9719->ctrls.handler);
@@ -232,26 +312,24 @@ static int dw9719_probe(struct i2c_client *client)
if (!dw9719)
return -ENOMEM;
- dw9719->regmap = devm_cci_regmap_init_i2c(client, 8);
- if (IS_ERR(dw9719->regmap))
- return PTR_ERR(dw9719->regmap);
-
+ dw9719->client = client;
dw9719->dev = &client->dev;
- dw9719->sac_mode = DW9719_MODE_SAC3;
- dw9719->vcm_freq = DW9719_DEFAULT_VCM_FREQ;
- /* Optional indication of SAC mode select */
- device_property_read_u32(&client->dev, "dongwoon,sac-mode",
- &dw9719->sac_mode);
-
- /* Optional indication of VCM frequency */
- device_property_read_u32(&client->dev, "dongwoon,vcm-freq",
- &dw9719->vcm_freq);
+ dw9719->regulators[0].supply = "vdd";
+ /*
+ * The DW9719 has only the 1 VDD voltage input, but some PMICs such as
+ * the TPS68470 PMIC have I2C passthrough capability, to disconnect the
+ * sensor's I2C pins from the I2C bus when the sensors VSIO (Sensor-IO)
+ * is off, because some sensors then short these pins to ground;
+ * and the DW9719 might sit behind this passthrough, this it needs to
+ * enable VSIO as that will also enable the I2C passthrough.
+ */
+ dw9719->regulators[1].supply = "vsio";
- dw9719->regulator = devm_regulator_get(&client->dev, "vdd");
- if (IS_ERR(dw9719->regulator))
- return dev_err_probe(&client->dev, PTR_ERR(dw9719->regulator),
- "getting regulator\n");
+ ret = devm_regulator_bulk_get(&client->dev, NUM_REGULATORS,
+ dw9719->regulators);
+ if (ret)
+ return dev_err_probe(&client->dev, ret, "getting regulators\n");
v4l2_i2c_subdev_init(&dw9719->sd, client, &dw9719_ops);
dw9719->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
@@ -312,17 +390,13 @@ static int dw9719_probe(struct i2c_client *client)
static void dw9719_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct dw9719_device *dw9719 =
- container_of(sd, struct dw9719_device, sd);
+ struct dw9719_device *dw9719 = container_of(sd, struct dw9719_device,
+ sd);
+ pm_runtime_disable(&client->dev);
v4l2_async_unregister_subdev(sd);
v4l2_ctrl_handler_free(&dw9719->ctrls.handler);
media_entity_cleanup(&dw9719->sd.entity);
-
- pm_runtime_disable(&client->dev);
- if (!pm_runtime_status_suspended(&client->dev))
- dw9719_power_down(dw9719);
- pm_runtime_set_suspended(&client->dev);
}
static const struct i2c_device_id dw9719_id_table[] = {
@@ -331,13 +405,14 @@ static const struct i2c_device_id dw9719_id_table[] = {
};
MODULE_DEVICE_TABLE(i2c, dw9719_id_table);
-static DEFINE_RUNTIME_DEV_PM_OPS(dw9719_pm_ops, dw9719_suspend, dw9719_resume,
- NULL);
+static const struct dev_pm_ops dw9719_pm_ops = {
+ SET_RUNTIME_PM_OPS(dw9719_suspend, dw9719_resume, NULL)
+};
static struct i2c_driver dw9719_i2c_driver = {
.driver = {
.name = "dw9719",
- .pm = pm_sleep_ptr(&dw9719_pm_ops),
+ .pm = &dw9719_pm_ops,
},
.probe = dw9719_probe,
.remove = dw9719_remove,
--
2.44.0
From bdbff69075918d01d32a57820aa845bde7be7611 Mon Sep 17 00:00:00 2001
From: mojyack <mojyack@gmail.com>
Date: Sat, 3 Feb 2024 12:59:53 +0900
Subject: [PATCH] media: staging: ipu3-imgu: Fix multiple calls of s_stream on
stream stop
Adapt to 009905e "media: v4l2-subdev: Document and enforce .s_stream() requirements"
---
drivers/staging/media/ipu3/ipu3-v4l2.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c
index 55cc44a401bc..9c5627c48cf2 100644
--- a/drivers/staging/media/ipu3/ipu3-v4l2.c
+++ b/drivers/staging/media/ipu3/ipu3-v4l2.c
@@ -538,18 +538,18 @@ static void imgu_vb2_stop_streaming(struct vb2_queue *vq)
WARN_ON(!node->enabled);
- pipe = node->pipe;
- dev_dbg(dev, "Try to stream off node [%u][%u]", pipe, node->id);
- imgu_pipe = &imgu->imgu_pipe[pipe];
- r = v4l2_subdev_call(&imgu_pipe->imgu_sd.subdev, video, s_stream, 0);
- if (r)
- dev_err(&imgu->pci_dev->dev,
- "failed to stop subdev streaming\n");
-
mutex_lock(&imgu->streaming_lock);
/* Was this the first node with streaming disabled? */
if (imgu->streaming && imgu_all_nodes_streaming(imgu, node)) {
/* Yes, really stop streaming now */
+ pipe = node->pipe;
+ dev_dbg(dev, "Try to stream off node [%u][%u]", pipe, node->id);
+ imgu_pipe = &imgu->imgu_pipe[pipe];
+ r = v4l2_subdev_call(&imgu_pipe->imgu_sd.subdev, video, s_stream, 0);
+ if (r)
+ dev_err(&imgu->pci_dev->dev,
+ "failed to stop subdev streaming\n");
+
dev_dbg(dev, "IMGU streaming is ready to stop");
r = imgu_s_stream(imgu, false);
if (!r)
--
2.44.0