@@ -85,6 +85,7 @@ struct rzg2l_adc {
struct reset_control *adrstn;
const struct rzg2l_adc_data *data;
const struct rzg2l_adc_hw_params *hw_params;
+ void *devres_group_id;
struct completion completion;
struct mutex lock;
u16 last_val[RZG2L_ADC_MAX_CHANNELS];
@@ -424,7 +425,7 @@ static int rzg2l_adc_hw_init(struct device *dev, struct rzg2l_adc *adc)
return ret;
}
-static int rzg2l_adc_probe(struct platform_device *pdev)
+static int rzg2l_adc_probe_helper(struct platform_device *pdev, void *devres_group_id)
{
struct device *dev = &pdev->dev;
struct iio_dev *indio_dev;
@@ -438,6 +439,7 @@ static int rzg2l_adc_probe(struct platform_device *pdev)
adc = iio_priv(indio_dev);
+ adc->devres_group_id = devres_group_id;
adc->hw_params = device_get_match_data(dev);
if (!adc->hw_params || adc->hw_params->num_channels > RZG2L_ADC_MAX_CHANNELS)
return -EINVAL;
@@ -495,6 +497,39 @@ static int rzg2l_adc_probe(struct platform_device *pdev)
return devm_iio_device_register(dev, indio_dev);
}
+static int rzg2l_adc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ void *devres_group_id;
+ int ret;
+
+ /*
+ * Open a devres group to allow using devm_pm_runtime_enable()
+ * w/o interfeering with dev_pm_genpd_detach() in the platform bus
+ * remove. Otherwise, durring repeated unbind/bind operations,
+ * the ADC may be runtime resumed when it is not part of its power
+ * domain, leading to accessing ADC registers without its clocks
+ * being enabled and its PM domain being turned on.
+ */
+ devres_group_id = devres_open_group(dev, NULL, GFP_KERNEL);
+ if (!devres_group_id)
+ return -ENOMEM;
+
+ ret = rzg2l_adc_probe_helper(pdev, devres_group_id);
+ if (ret)
+ devres_release_group(dev, devres_group_id);
+
+ return ret;
+}
+
+static void rzg2l_adc_remove(struct platform_device *pdev)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct rzg2l_adc *adc = iio_priv(indio_dev);
+
+ devres_release_group(&pdev->dev, adc->devres_group_id);
+}
+
static const struct rzg2l_adc_hw_params rzg2l_hw_params = {
.num_channels = 8,
.default_adcmp = 0xe,
@@ -614,6 +649,7 @@ static const struct dev_pm_ops rzg2l_adc_pm_ops = {
static struct platform_driver rzg2l_adc_driver = {
.probe = rzg2l_adc_probe,
+ .remove = rzg2l_adc_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = rzg2l_adc_match,