Skip to contentSkip to conversation

media: Add regulator support to ov9282

PATCH In review Dave Stevenson 4 participants 9 messages Oct 5, 2022 – Nov 24, 2022

Subsystems (4)
lore
Share & tools
lore

Dave Stevenson

author maintainer
#0 lore raw

cover media: Add regulator support to ov9282

The sensor takes 3 voltage supply rails, so add the relevant configuration to the device tree bindings and driver.

Dave Stevenson (2):
dt-bindings: media: ovti,ov9282: Add optional regulators
media: i2c: ov9282: Add support for regulators.

 .../bindings/media/i2c/ovti,ov9282.yaml       |  9 +++++
 drivers/media/i2c/ov9282.c                    | 38 +++++++++++++++++++
 2 files changed, 47 insertions(+)
Signature · 1 line
2.34.1
author maintainer
#1 lore raw

PATCH 1/2 dt-bindings: media: ovti,ov9282: Add optional regulators

The OV9282 image sensor takes 3 voltage supplies, so define the relevant regulators.

---
 .../devicetree/bindings/media/i2c/ovti,ov9282.yaml       | 9 +++++++++
 1 file changed, 9 insertions(+)
Documentation/devicetree/bindings/media/i2c/ovti,ov9282.yaml +9 -0
index bf115ab9d926..652b4cfeded7 100644
@@ -36,6 +36,15 @@ properties:
     description: Reference to the GPIO connected to the XCLR pin, if any.
     maxItems: 1
 
+  avdd-supply:
+    description: Analog voltage supply, 2.8 volts
+
+  dvdd-supply:
+    description: Digital core voltage supply, 1.2 volts
+
+  dovdd-supply:
+    description: Digital I/O voltage supply, 1.8 volts
+
   port:
     additionalProperties: false
     $ref: /schemas/graph.yaml#/$defs/port-base
Signature · 1 line
2.34.1
maintainer Acked-by on v1 1/2
#2 lore raw

Re: [PATCH 1/2] dt-bindings: media: ovti,ov9282: Add optional regulators

Quoted 8 lines · Dave Stevenson

The OV9282 image sensor takes 3 voltage supplies, so define the relevant regulators.

---
 .../devicetree/bindings/media/i2c/ovti,ov9282.yaml       | 9 +++++++++
 1 file changed, 9 insertions(+)
author maintainer
#3 lore raw

PATCH 2/2 media: i2c: ov9282: Add support for regulators.

In reply to Dave Stevenson

The sensor takes 3 supply rails - AVDD, DVDD, and DOVDD.

Add hooks into the regulator framework for each of these regulators.

---
 drivers/media/i2c/ov9282.c | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)
drivers/media/i2c/ov9282.c +38 -0
index 2e0b315801e5..699fc5b753b4 100644
@@ -11,6 +11,7 @@
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
 
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-fwnode.h>
@@ -55,6 +56,14 @@
 #define OV9282_REG_MIN		0x00
 #define OV9282_REG_MAX		0xfffff
 
+static const char * const ov9282_supply_names[] = {
+	"avdd",		/* Analog power */
+	"dovdd",	/* Digital I/O power */
+	"dvdd",		/* Digital core power */
+};
+
+#define OV9282_NUM_SUPPLIES ARRAY_SIZE(ov9282_supply_names)
+
 /**
  * struct ov9282_reg - ov9282 sensor register
  * @address: Register address
@@ -128,6 +137,7 @@ struct ov9282 {
 	struct media_pad pad;
 	struct gpio_desc *reset_gpio;
 	struct clk *inclk;
+	struct regulator_bulk_data supplies[OV9282_NUM_SUPPLIES];
 	struct v4l2_ctrl_handler ctrl_handler;
 	struct v4l2_ctrl *link_freq_ctrl;
 	struct v4l2_ctrl *pclk_ctrl;
@@ -767,6 +777,18 @@ static int ov9282_detect(struct ov9282 *ov9282)
 	return 0;
 }
 
+static int ov9282_configure_regulators(struct ov9282 *ov9282)
+{
+	unsigned int i;
+
+	for (i = 0; i < OV9282_NUM_SUPPLIES; i++)
+		ov9282->supplies[i].supply = ov9282_supply_names[i];
+
+	return devm_regulator_bulk_get(ov9282->dev,
+				       OV9282_NUM_SUPPLIES,
+				       ov9282->supplies);
+}
+
 /**
  * ov9282_parse_hw_config() - Parse HW configuration and check if supported
  * @ov9282: pointer to ov9282 device
@@ -803,6 +825,12 @@ static int ov9282_parse_hw_config(struct ov9282 *ov9282)
 		return PTR_ERR(ov9282->inclk);
 	}
 
+	ret = ov9282_configure_regulators(ov9282);
+	if (ret) {
+		dev_err(ov9282->dev, "Failed to get power regulators\n");
+		return ret;
+	}
+
 	rate = clk_get_rate(ov9282->inclk);
 	if (rate != OV9282_INCLK_RATE) {
 		dev_err(ov9282->dev, "inclk frequency mismatch");
@@ -874,6 +902,12 @@ static int ov9282_power_on(struct device *dev)
 	struct ov9282 *ov9282 = to_ov9282(sd);
 	int ret;
 
+	ret = regulator_bulk_enable(OV9282_NUM_SUPPLIES, ov9282->supplies);
+	if (ret < 0) {
+		dev_err(dev, "Failed to enable regulators\n");
+		return ret;
+	}
+
 	usleep_range(400, 600);
 
 	gpiod_set_value_cansleep(ov9282->reset_gpio, 1);
@@ -891,6 +925,8 @@ static int ov9282_power_on(struct device *dev)
 error_reset:
 	gpiod_set_value_cansleep(ov9282->reset_gpio, 0);
 
+	regulator_bulk_disable(OV9282_NUM_SUPPLIES, ov9282->supplies);
+
 	return ret;
 }
 
@@ -909,6 +945,8 @@ static int ov9282_power_off(struct device *dev)
 
 	clk_disable_unprepare(ov9282->inclk);
 
+	regulator_bulk_disable(OV9282_NUM_SUPPLIES, ov9282->supplies);
+
 	return 0;
 }
 
Signature · 1 line
2.34.1
Acked-by on v1 2/2
#4 lore raw

Re: [PATCH 2/2] media: i2c: ov9282: Add support for regulators.

Hello Dave,

Am Mittwoch, 5. Oktober 2022, 17:20:18 CET schrieb Dave Stevenson:

Quoted 38 lines

The sensor takes 3 supply rails - AVDD, DVDD, and DOVDD.

Add hooks into the regulator framework for each of these regulators.

---
 drivers/media/i2c/ov9282.c | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)
drivers/media/i2c/ov9282.c +9 -0
index 2e0b315801e5..699fc5b753b4 100644
@@ -11,6 +11,7 @@
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
 
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-fwnode.h>
@@ -55,6 +56,14 @@
 #define OV9282_REG_MIN		0x00
 #define OV9282_REG_MAX		0xfffff
 
+static const char * const ov9282_supply_names[] = {
+	"avdd",		/* Analog power */
+	"dovdd",	/* Digital I/O power */
+	"dvdd",		/* Digital core power */
+};
+
+#define OV9282_NUM_SUPPLIES ARRAY_SIZE(ov9282_supply_names)
+
 /**
  * struct ov9282_reg - ov9282 sensor register
  * @address: Register address

drivers/media/i2c/ov9282.c struct ov9282 { · line 140

Quoted 4 lines
drivers/media/i2c/ov9282.c +1 -0
@@ -128,6 +137,7 @@ struct ov9282 {
 	struct media_pad pad;
 	struct gpio_desc *reset_gpio;
 	struct clk *inclk;
+	struct regulator_bulk_data supplies[OV9282_NUM_SUPPLIES];

Please add documentation for supplies.

Quoted 23 lines
drivers/media/i2c/ov9282.c +12 -0
 	struct v4l2_ctrl_handler ctrl_handler;
 	struct v4l2_ctrl *link_freq_ctrl;
 	struct v4l2_ctrl *pclk_ctrl;
@@ -767,6 +777,18 @@ static int ov9282_detect(struct ov9282 *ov9282)
 	return 0;
 }
 
+static int ov9282_configure_regulators(struct ov9282 *ov9282)
+{
+	unsigned int i;
+
+	for (i = 0; i < OV9282_NUM_SUPPLIES; i++)
+		ov9282->supplies[i].supply = ov9282_supply_names[i];
+
+	return devm_regulator_bulk_get(ov9282->dev,
+				       OV9282_NUM_SUPPLIES,
+				       ov9282->supplies);
+}
+
 /**
  * ov9282_parse_hw_config() - Parse HW configuration and check if supported
 * @ov9282: pointer to ov9282 device

drivers/media/i2c/ov9282.c static int ov9282_parse_hw_config(struct ov9282 · line 830

Quoted 6 lines
drivers/media/i2c/ov9282.c +3 -0
@@ -803,6 +825,12 @@ static int ov9282_parse_hw_config(struct ov9282
 *ov9282) return PTR_ERR(ov9282->inclk);
 	}
 
+	ret = ov9282_configure_regulators(ov9282);
+	if (ret) {
+		dev_err(ov9282->dev, "Failed to get power regulators\n");

dev_err_probe seems sensible here.

Quoted 29 lines
drivers/media/i2c/ov9282.c +11 -0
+		return ret;
+	}
+
 	rate = clk_get_rate(ov9282->inclk);
 	if (rate != OV9282_INCLK_RATE) {
 		dev_err(ov9282->dev, "inclk frequency mismatch");
@@ -874,6 +902,12 @@ static int ov9282_power_on(struct device *dev)
 	struct ov9282 *ov9282 = to_ov9282(sd);
 	int ret;
 
+	ret = regulator_bulk_enable(OV9282_NUM_SUPPLIES, ov9282->supplies);
+	if (ret < 0) {
+		dev_err(dev, "Failed to enable regulators\n");
+		return ret;
+	}
+
 	usleep_range(400, 600);
 
 	gpiod_set_value_cansleep(ov9282->reset_gpio, 1);
@@ -891,6 +925,8 @@ static int ov9282_power_on(struct device *dev)
 error_reset:
 	gpiod_set_value_cansleep(ov9282->reset_gpio, 0);
 
+	regulator_bulk_disable(OV9282_NUM_SUPPLIES, ov9282->supplies);
+
 	return ret;
 }
 

drivers/media/i2c/ov9282.c static int ov9282_power_off(struct device *dev) · line 951

Quoted 7 lines
drivers/media/i2c/ov9282.c +2 -0
@@ -909,6 +945,8 @@ static int ov9282_power_off(struct device *dev)
 
 	clk_disable_unprepare(ov9282->inclk);
 
+	regulator_bulk_disable(OV9282_NUM_SUPPLIES, ov9282->supplies);
+
 	return 0;
 }

Despite the nits above

author maintainer
#5 lore raw

Re: [PATCH 2/2] media: i2c: ov9282: Add support for regulators.

Hi Alexander

Thanks for the review.

Sakari has already picked this up and included it in a pull to Mauro for 6.2.
https://www.spinics.net/lists/linux-media/msg222346.html

Quoted 40 lines · Alexander Stein

Hello Dave,

Am Mittwoch, 5. Oktober 2022, 17:20:18 CET schrieb Dave Stevenson:

Quoted 36 lines

The sensor takes 3 supply rails - AVDD, DVDD, and DOVDD.

Add hooks into the regulator framework for each of these regulators.

---
 drivers/media/i2c/ov9282.c | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)
drivers/media/i2c/ov9282.c +9 -0
index 2e0b315801e5..699fc5b753b4 100644
@@ -11,6 +11,7 @@
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
 
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-fwnode.h>
@@ -55,6 +56,14 @@
 #define OV9282_REG_MIN               0x00
 #define OV9282_REG_MAX               0xfffff
 
+static const char * const ov9282_supply_names[] = {
+     "avdd",         /* Analog power */
+     "dovdd",        /* Digital I/O power */
+     "dvdd",         /* Digital core power */
+};
+
+#define OV9282_NUM_SUPPLIES ARRAY_SIZE(ov9282_supply_names)
+
 /**
  * struct ov9282_reg - ov9282 sensor register
Quoted 8 lines

drivers/media/i2c/ov9282.c struct ov9282 { · line 140

Quoted 6 lines
drivers/media/i2c/ov9282.c +1 -0
  * @address: Register address
@@ -128,6 +137,7 @@ struct ov9282 {
      struct media_pad pad;
      struct gpio_desc *reset_gpio;
      struct clk *inclk;
+     struct regulator_bulk_data supplies[OV9282_NUM_SUPPLIES];

Please add documentation for supplies.

Is it the place for the driver to document the supplies beyond the comments in ov9282_supply_names with regard to which sensor rail they relate to?
Some drivers include the typical values for each supply, but those are technically inaccurate as each will have a min and max value.

Anyone interfacing with a sensor is going to have the datasheet for it and should be referring to that for the characteristics of supply rails. Duplicating some of that in the driver seems redundant, and has the potential to be incorrect.

Quoted 26 lines
Quoted 26 lines
drivers/media/i2c/ov9282.c +12 -0
      struct v4l2_ctrl_handler ctrl_handler;
      struct v4l2_ctrl *link_freq_ctrl;
      struct v4l2_ctrl *pclk_ctrl;
@@ -767,6 +777,18 @@ static int ov9282_detect(struct ov9282 *ov9282)
      return 0;
 }
 
+static int ov9282_configure_regulators(struct ov9282 *ov9282)
+{
+     unsigned int i;
+
+     for (i = 0; i < OV9282_NUM_SUPPLIES; i++)
+             ov9282->supplies[i].supply = ov9282_supply_names[i];
+
+     return devm_regulator_bulk_get(ov9282->dev,
+                                    OV9282_NUM_SUPPLIES,
+                                    ov9282->supplies);
+}
+
 /**
  * ov9282_parse_hw_config() - Parse HW configuration and check if supported
 * @ov9282: pointer to ov9282 device
@@ -803,6 +825,12 @@ static int ov9282_parse_hw_config(struct ov9282
 *ov9282) return PTR_ERR(ov9282->inclk);
      }
 
Quoted 5 lines

drivers/media/i2c/ov9282.c static int ov9282_parse_hw_config(struct ov9282 *ov9282) · line 830

Quoted 3 lines
drivers/media/i2c/ov9282.c +3 -0
+     ret = ov9282_configure_regulators(ov9282);
+     if (ret) {
+             dev_err(ov9282->dev, "Failed to get power regulators\n");

dev_err_probe seems sensible here.

That would have been good - sorry. I must get into the habit of remembering to use dev_err_probe.

Dave

Quoted 39 lines
Quoted 29 lines
drivers/media/i2c/ov9282.c +11 -0
+             return ret;
+     }
+
      rate = clk_get_rate(ov9282->inclk);
      if (rate != OV9282_INCLK_RATE) {
              dev_err(ov9282->dev, "inclk frequency mismatch");
@@ -874,6 +902,12 @@ static int ov9282_power_on(struct device *dev)
      struct ov9282 *ov9282 = to_ov9282(sd);
      int ret;
 
+     ret = regulator_bulk_enable(OV9282_NUM_SUPPLIES, ov9282->supplies);
+     if (ret < 0) {
+             dev_err(dev, "Failed to enable regulators\n");
+             return ret;
+     }
+
      usleep_range(400, 600);
 
      gpiod_set_value_cansleep(ov9282->reset_gpio, 1);
@@ -891,6 +925,8 @@ static int ov9282_power_on(struct device *dev)
 error_reset:
      gpiod_set_value_cansleep(ov9282->reset_gpio, 0);
 
+     regulator_bulk_disable(OV9282_NUM_SUPPLIES, ov9282->supplies);
+
      return ret;
 }
 

drivers/media/i2c/ov9282.c static int ov9282_power_off(struct device *dev) · line 951

Quoted 7 lines
drivers/media/i2c/ov9282.c +2 -0
@@ -909,6 +945,8 @@ static int ov9282_power_off(struct device *dev)
 
      clk_disable_unprepare(ov9282->inclk);
 
+     regulator_bulk_disable(OV9282_NUM_SUPPLIES, ov9282->supplies);
+
      return 0;
 }

Despite the nits above

#6 lore raw

Re: [PATCH 2/2] media: i2c: ov9282: Add support for regulators.

Hi Dave,

Am Donnerstag, 24. November 2022, 12:58:08 CET schrieb Dave Stevenson:

Quoted 6 lines

Hi Alexander

Thanks for the review.

Sakari has already picked this up and included it in a pull to Mauro for 6.2. https://www.spinics.net/lists/linux-media/msg222346.html

A quite recent, I wasn't aware of that. Thanks for the hint.

Quoted 67 lines

On Thu, 24 Nov 2022 at 09:31, Alexander Stein

Quoted 50 lines · <[email protected]> wrote:

Hello Dave,

Am Mittwoch, 5. Oktober 2022, 17:20:18 CET schrieb Dave Stevenson:

Quoted 47 lines

The sensor takes 3 supply rails - AVDD, DVDD, and DOVDD.

Add hooks into the regulator framework for each of these regulators.

---

 drivers/media/i2c/ov9282.c | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)
drivers/media/i2c/ov9282.c +1 -0
index 2e0b315801e5..699fc5b753b4 100644
@@ -11,6 +11,7 @@
 
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
 
+#include <linux/regulator/consumer.h>
 

#include <media/v4l2-ctrls.h>
#include <media/v4l2-fwnode.h>

drivers/media/i2c/ov9282.c +8 -0
@@ -55,6 +56,14 @@
 
 #define OV9282_REG_MIN               0x00
 #define OV9282_REG_MAX               0xfffff
 
+static const char * const ov9282_supply_names[] = {
+     "avdd",         /* Analog power */
+     "dovdd",        /* Digital I/O power */
+     "dvdd",         /* Digital core power */
+};
+
+#define OV9282_NUM_SUPPLIES ARRAY_SIZE(ov9282_supply_names)
+
 
 /**

* struct ov9282_reg - ov9282 sensor register
* @address: Register address

drivers/media/i2c/ov9282.c +0 -0
@@ -128,6 +137,7 @@ struct ov9282 {
 
Quoted 7 lines

drivers/media/i2c/ov9282.c struct ov9282 { · line 140

Quoted 5 lines
drivers/media/i2c/ov9282.c +1 -0
      struct media_pad pad;
      struct gpio_desc *reset_gpio;
      struct clk *inclk;
 
+     struct regulator_bulk_data supplies[OV9282_NUM_SUPPLIES];

Please add documentation for supplies.

Is it the place for the driver to document the supplies beyond the comments in ov9282_supply_names with regard to which sensor rail they relate to?
Some drivers include the typical values for each supply, but those are technically inaccurate as each will have a min and max value.

Quoted 4 lines

Anyone interfacing with a sensor is going to have the datasheet for it and should be referring to that for the characteristics of supply rails. Duplicating some of that in the driver seems redundant, and has the potential to be incorrect.

What I meant was adding " @supplies: power supply regulators" to the doxygen (?) documentation directly above.
I agree that no details about those supplies should be added to driver code though.

Alexander

Quoted 97 lines
Quoted 33 lines
Quoted 33 lines
drivers/media/i2c/ov9282.c +0 -0
      struct v4l2_ctrl_handler ctrl_handler;
      struct v4l2_ctrl *link_freq_ctrl;
      struct v4l2_ctrl *pclk_ctrl;
drivers/media/i2c/ov9282.c +12 -0
@@ -767,6 +777,18 @@ static int ov9282_detect(struct ov9282 *ov9282)
 
      return 0;
 
 }
 
+static int ov9282_configure_regulators(struct ov9282 *ov9282)
+{
+     unsigned int i;
+
+     for (i = 0; i < OV9282_NUM_SUPPLIES; i++)
+             ov9282->supplies[i].supply = ov9282_supply_names[i];
+
+     return devm_regulator_bulk_get(ov9282->dev,
+                                    OV9282_NUM_SUPPLIES,
+                                    ov9282->supplies);
+}
+
 

/**

* ov9282_parse_hw_config() - Parse HW configuration and check if supported

* @ov9282: pointer to ov9282 device

drivers/media/i2c/ov9282.c +0 -0
@@ -803,6 +825,12 @@ static int ov9282_parse_hw_config(struct ov9282
 *ov9282) return PTR_ERR(ov9282->inclk);
 
Quoted 7 lines

drivers/media/i2c/ov9282.c static int ov9282_parse_hw_config(struct ov9282 *ov9282) · line 830

Quoted 5 lines
drivers/media/i2c/ov9282.c +3 -0
      }
 
+     ret = ov9282_configure_regulators(ov9282);
+     if (ret) {
+             dev_err(ov9282->dev, "Failed to get power regulators\n");

dev_err_probe seems sensible here.

That would have been good - sorry. I must get into the habit of remembering to use dev_err_probe.

Dave

Quoted 51 lines
Quoted 47 lines
drivers/media/i2c/ov9282.c +3 -0
+             return ret;
+     }
+
 
      rate = clk_get_rate(ov9282->inclk);
      if (rate != OV9282_INCLK_RATE) {
      
              dev_err(ov9282->dev, "inclk frequency mismatch");
drivers/media/i2c/ov9282.c +6 -0
@@ -874,6 +902,12 @@ static int ov9282_power_on(struct device *dev)
 
      struct ov9282 *ov9282 = to_ov9282(sd);
      int ret;
 
+     ret = regulator_bulk_enable(OV9282_NUM_SUPPLIES,
 ov9282->supplies);
+     if (ret < 0) {
+             dev_err(dev, "Failed to enable regulators\n");
+             return ret;
+     }
+
 
      usleep_range(400, 600);
      
      gpiod_set_value_cansleep(ov9282->reset_gpio, 1);
drivers/media/i2c/ov9282.c +2 -0
@@ -891,6 +925,8 @@ static int ov9282_power_on(struct device *dev)
 
 error_reset:
      gpiod_set_value_cansleep(ov9282->reset_gpio, 0);
 
+     regulator_bulk_disable(OV9282_NUM_SUPPLIES, ov9282->supplies);
+
 
      return ret;

}

drivers/media/i2c/ov9282.c +2 -0
@@ -909,6 +945,8 @@ static int ov9282_power_off(struct device *dev)
 
      clk_disable_unprepare(ov9282->inclk);
 
+     regulator_bulk_disable(OV9282_NUM_SUPPLIES, ov9282->supplies);
+
 
      return 0;
 
Quoted 1 line

}

Despite the nits above

author maintainer
#7 lore raw
In reply to Dave Stevenson
Quoted 3 lines · Dave Stevenson

The sensor takes 3 voltage supply rails, so add the relevant configuration to the device tree bindings and driver.

A gentle ping to this patchset.
The other patchset for ov9282 that added functionality has been merged and made a pull request already, and Patchwork was reporting this one as "Under review" for longer than that one was.
The DT side is ack'ed, and the driver changes are pretty trivial.

Cheers,
Dave

Quoted 11 lines

Dave Stevenson (2):
dt-bindings: media: ovti,ov9282: Add optional regulators
media: i2c: ov9282: Add support for regulators.

 .../bindings/media/i2c/ovti,ov9282.yaml       |  9 +++++
 drivers/media/i2c/ov9282.c                    | 38 +++++++++++++++++++
 2 files changed, 47 insertions(+)

--
2.34.1

#8 lore raw

Hi Dave,

Quoted 11 lines · Dave Stevenson
Quoted 3 lines · Dave Stevenson

The sensor takes 3 voltage supply rails, so add the relevant configuration to the device tree bindings and driver.

A gentle ping to this patchset.
The other patchset for ov9282 that added functionality has been merged and made a pull request already, and Patchwork was reporting this one as "Under review" for longer than that one was.
The DT side is ack'ed, and the driver changes are pretty trivial.

Oops.

Thanks for the ping. These are in my tree now.

Signature · 3 lines
Kind regards,

Sakari Ailus