bcm27xx: 6.1: add kernel patches
[openwrt/staging/nbd.git] / target / linux / bcm27xx / patches-6.1 / 950-0644-media-i2c-imx290-Initialize-runtime-PM-before-subdev.patch
1 From 42d779016414396fe047ef41af6bc8297f3cd6a4 Mon Sep 17 00:00:00 2001
2 From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
3 Date: Mon, 16 Jan 2023 15:44:51 +0100
4 Subject: [PATCH] media: i2c: imx290: Initialize runtime PM before
5 subdev
6
7 Upstream commit 02852c01f654
8
9 Initializing the subdev before runtime PM means that no subdev
10 initialization can interact with the runtime PM framework. This can be
11 problematic when modifying controls, as the .s_ctrl() handler commonly
12 calls pm_runtime_get_if_in_use(). These code paths are not trivial,
13 making the driver fragile and possibly causing subtle bugs.
14
15 To make the subdev initialization more robust, initialize runtime PM
16 first.
17
18 Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
19 Acked-by: Alexander Stein <alexander.stein@ew.tq-group.com>
20 Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
21 Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
22 ---
23 drivers/media/i2c/imx290.c | 59 ++++++++++++++++++++++----------------
24 1 file changed, 34 insertions(+), 25 deletions(-)
25
26 --- a/drivers/media/i2c/imx290.c
27 +++ b/drivers/media/i2c/imx290.c
28 @@ -581,9 +581,7 @@ static int imx290_set_ctrl(struct v4l2_c
29
30 /*
31 * Return immediately for controls that don't need to be applied to the
32 - * device. Those controls are modified in imx290_ctrl_update(), which
33 - * is called at probe time before runtime PM is initialized, so we
34 - * can't proceed to the pm_runtime_get_if_in_use() call below.
35 + * device.
36 */
37 if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)
38 return 0;
39 @@ -1049,22 +1047,20 @@ static void imx290_subdev_cleanup(struct
40 * Power management
41 */
42
43 -static int imx290_power_on(struct device *dev)
44 +static int imx290_power_on(struct imx290 *imx290)
45 {
46 - struct v4l2_subdev *sd = dev_get_drvdata(dev);
47 - struct imx290 *imx290 = to_imx290(sd);
48 int ret;
49
50 ret = clk_prepare_enable(imx290->xclk);
51 if (ret) {
52 - dev_err(dev, "Failed to enable clock\n");
53 + dev_err(imx290->dev, "Failed to enable clock\n");
54 return ret;
55 }
56
57 ret = regulator_bulk_enable(ARRAY_SIZE(imx290->supplies),
58 imx290->supplies);
59 if (ret) {
60 - dev_err(dev, "Failed to enable regulators\n");
61 + dev_err(imx290->dev, "Failed to enable regulators\n");
62 clk_disable_unprepare(imx290->xclk);
63 return ret;
64 }
65 @@ -1079,20 +1075,33 @@ static int imx290_power_on(struct device
66 return 0;
67 }
68
69 -static int imx290_power_off(struct device *dev)
70 +static void imx290_power_off(struct imx290 *imx290)
71 {
72 - struct v4l2_subdev *sd = dev_get_drvdata(dev);
73 - struct imx290 *imx290 = to_imx290(sd);
74 -
75 clk_disable_unprepare(imx290->xclk);
76 gpiod_set_value_cansleep(imx290->rst_gpio, 1);
77 regulator_bulk_disable(ARRAY_SIZE(imx290->supplies), imx290->supplies);
78 +}
79 +
80 +static int imx290_runtime_resume(struct device *dev)
81 +{
82 + struct v4l2_subdev *sd = dev_get_drvdata(dev);
83 + struct imx290 *imx290 = to_imx290(sd);
84 +
85 + return imx290_power_on(imx290);
86 +}
87 +
88 +static int imx290_runtime_suspend(struct device *dev)
89 +{
90 + struct v4l2_subdev *sd = dev_get_drvdata(dev);
91 + struct imx290 *imx290 = to_imx290(sd);
92 +
93 + imx290_power_off(imx290);
94
95 return 0;
96 }
97
98 static const struct dev_pm_ops imx290_pm_ops = {
99 - SET_RUNTIME_PM_OPS(imx290_power_off, imx290_power_on, NULL)
100 + SET_RUNTIME_PM_OPS(imx290_runtime_suspend, imx290_runtime_resume, NULL)
101 };
102
103 /* ----------------------------------------------------------------------------
104 @@ -1271,20 +1280,15 @@ static int imx290_probe(struct i2c_clien
105 if (ret)
106 return ret;
107
108 - /* Initialize the V4L2 subdev. */
109 - ret = imx290_subdev_init(imx290);
110 - if (ret)
111 - return ret;
112 -
113 /*
114 * Enable power management. The driver supports runtime PM, but needs to
115 * work when runtime PM is disabled in the kernel. To that end, power
116 * the sensor on manually here.
117 */
118 - ret = imx290_power_on(dev);
119 + ret = imx290_power_on(imx290);
120 if (ret < 0) {
121 dev_err(dev, "Could not power on the device\n");
122 - goto err_subdev;
123 + return ret;
124 }
125
126 /*
127 @@ -1298,6 +1302,11 @@ static int imx290_probe(struct i2c_clien
128 pm_runtime_set_autosuspend_delay(dev, 1000);
129 pm_runtime_use_autosuspend(dev);
130
131 + /* Initialize the V4L2 subdev. */
132 + ret = imx290_subdev_init(imx290);
133 + if (ret)
134 + goto err_pm;
135 +
136 /*
137 * Finally, register the V4L2 subdev. This must be done after
138 * initializing everything as the subdev can be used immediately after
139 @@ -1306,7 +1315,7 @@ static int imx290_probe(struct i2c_clien
140 ret = v4l2_async_register_subdev(&imx290->sd);
141 if (ret < 0) {
142 dev_err(dev, "Could not register v4l2 device\n");
143 - goto err_pm;
144 + goto err_subdev;
145 }
146
147 /*
148 @@ -1318,12 +1327,12 @@ static int imx290_probe(struct i2c_clien
149
150 return 0;
151
152 +err_subdev:
153 + imx290_subdev_cleanup(imx290);
154 err_pm:
155 pm_runtime_disable(dev);
156 pm_runtime_put_noidle(dev);
157 - imx290_power_off(dev);
158 -err_subdev:
159 - imx290_subdev_cleanup(imx290);
160 + imx290_power_off(imx290);
161 return ret;
162 }
163
164 @@ -1341,7 +1350,7 @@ static void imx290_remove(struct i2c_cli
165 */
166 pm_runtime_disable(imx290->dev);
167 if (!pm_runtime_status_suspended(imx290->dev))
168 - imx290_power_off(imx290->dev);
169 + imx290_power_off(imx290);
170 pm_runtime_set_suspended(imx290->dev);
171 }
172