RE: [PATCH v5 1/3] iio: adc: add imx93 adc support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> -----Original Message-----
> From: Jonathan Cameron <jic23@xxxxxxxxxx>
> Sent: 2023年1月8日 21:22
> To: Bough Chen <haibo.chen@xxxxxxx>
> Cc: lars@xxxxxxxxxx; robh+dt@xxxxxxxxxx; krzysztof.kozlowski+dt@xxxxxxxxxx;
> shawnguo@xxxxxxxxxx; s.hauer@xxxxxxxxxxxxxx; kernel@xxxxxxxxxxxxxx;
> festevam@xxxxxxxxx; dl-linux-imx <linux-imx@xxxxxxx>;
> linux-iio@xxxxxxxxxxxxxxx; devicetree@xxxxxxxxxxxxxxx
> Subject: Re: [PATCH v5 1/3] iio: adc: add imx93 adc support
> 
> On Tue,  3 Jan 2023 19:43:56 +0800
> haibo.chen@xxxxxxx wrote:
> 
> > From: Haibo Chen <haibo.chen@xxxxxxx>
> >
> > The ADC in i.mx93 is a total new ADC IP, add a driver to support this
> > ADC.
> >
> > Currently, only support one shot normal conversion triggered by
> > software. For other mode, will add in future.
> >
> > Signed-off-by: Haibo Chen <haibo.chen@xxxxxxx>
> Hi Haibo,
> 
> I'm still not sure about the power handling in remove. One other minor
> comment inline that would be good to clean up for v6.
> 
> Thanks,
> 
> Jonathan
> 
> > new file mode 100644
> > index 000000000000..0c98de438919
> > --- /dev/null
> > +++ b/drivers/iio/adc/imx93_adc.c
> 
> ...
> 
> > +
> > +static int imx93_adc_calibration(struct imx93_adc *adc) {
> > +	u32 mcr, msr;
> > +	int ret;
> > +
> > +	/* make sure ADC in power down mode */
> > +	imx93_adc_power_down(adc);
> > +
> > +	/* config SAR controller operating clock */
> > +	mcr = readl(adc->regs + IMX93_ADC_MCR);
> > +	mcr &= ~FIELD_PREP(IMX93_ADC_MCR_ADCLKSE_MASK, 1);
> > +	writel(mcr, adc->regs + IMX93_ADC_MCR);
> > +
> > +	imx93_adc_power_up(adc);
> 
> I think this function should be side effect free on error to aid easy reviewing /
> code modularity. Thus if anything after this point fails, the device should be
> deliberately powered down again to remove that side effect.
> 
> > +
> > +	/*
> > +	 * TODO: we use the default TSAMP/NRSMPL/AVGEN in MCR,
> > +	 * can add the setting of these bit if need in future.
> > +	 */
> > +
> > +	/* run calibration */
> > +	mcr = readl(adc->regs + IMX93_ADC_MCR);
> > +	mcr |= FIELD_PREP(IMX93_ADC_MCR_CALSTART_MASK, 1);
> > +	writel(mcr, adc->regs + IMX93_ADC_MCR);
> > +
> > +	/* wait calibration to be finished */
> > +	ret = readl_poll_timeout(adc->regs + IMX93_ADC_MSR, msr,
> > +		!(msr & IMX93_ADC_MSR_CALBUSY_MASK), 1000, 2000000);
> > +	if (ret == -ETIMEDOUT) {
> > +		dev_warn(adc->dev, "ADC do not finish calibration in 1 min!\n");
> > +		return ret;
> > +	}
> > +
> > +	/* check whether calbration is success or not */
> > +	msr = readl(adc->regs + IMX93_ADC_MSR);
> > +	if (msr & IMX93_ADC_MSR_CALFAIL_MASK) {
> > +		dev_warn(adc->dev, "ADC calibration failed!\n");
> > +		return -EAGAIN;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> 
> ...
> 
> > +static int imx93_adc_probe(struct platform_device *pdev) {
> > +	struct imx93_adc *adc;
> > +	struct iio_dev *indio_dev;
> > +	struct device *dev = &pdev->dev;
> > +	int ret;
> > +
> > +	indio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
> > +	if (!indio_dev)
> > +		return dev_err_probe(dev, -ENOMEM,
> > +				     "Failed allocating iio device\n");
> > +
> > +	adc = iio_priv(indio_dev);
> > +	adc->dev = dev;
> > +
> > +	mutex_init(&adc->lock);
> > +	adc->regs = devm_platform_ioremap_resource(pdev, 0);
> > +	if (IS_ERR(adc->regs))
> > +		return dev_err_probe(dev, PTR_ERR(adc->regs),
> > +				     "Failed geting ioremap resource\n");
> > +
> > +	/* The third irq is for ADC conversion usage */
> > +	adc->irq = platform_get_irq(pdev, 2);
> > +	if (adc->irq < 0)
> > +		return adc->irq;
> > +
> > +	adc->ipg_clk = devm_clk_get(dev, "ipg");
> > +	if (IS_ERR(adc->ipg_clk))
> > +		return dev_err_probe(dev, PTR_ERR(adc->ipg_clk),
> > +				     "Failed getting clock.\n");
> > +
> > +	adc->vref = devm_regulator_get(dev, "vref");
> > +	if (IS_ERR(adc->vref))
> > +		return dev_err_probe(dev, PTR_ERR(adc->vref),
> > +				     "Failed getting reference voltage.\n");
> > +
> > +	ret = regulator_enable(adc->vref);
> > +	if (ret)
> > +		return dev_err_probe(dev, ret,
> > +				     "Failed to enable reference voltage.\n");
> > +
> > +	platform_set_drvdata(pdev, indio_dev);
> > +
> > +	init_completion(&adc->completion);
> > +
> > +	indio_dev->name = "imx93-adc";
> > +	indio_dev->info = &imx93_adc_iio_info;
> > +	indio_dev->modes = INDIO_DIRECT_MODE;
> > +	indio_dev->channels = imx93_adc_iio_channels;
> > +	indio_dev->num_channels = ARRAY_SIZE(imx93_adc_iio_channels);
> > +
> > +	ret = clk_prepare_enable(adc->ipg_clk);
> > +	if (ret) {
> > +		dev_err_probe(dev, ret,
> > +			      "Failed to enable ipg clock.\n");
> > +		goto error_regulator_disable;
> > +	}
> > +
> > +	ret = request_irq(adc->irq, imx93_adc_isr, 0, IMX93_ADC_DRIVER_NAME,
> adc);
> > +	if (ret < 0) {
> > +		dev_err_probe(dev, ret,
> > +			      "Failed requesting irq, irq = %d\n", adc->irq);
> > +		goto error_ipg_clk_disable;
> > +	}
> > +
> > +	ret = imx93_adc_calibration(adc);
> > +	if (ret < 0)
> 
> As above, I'd expect the device to be powered down if this function fails and
> hence need an additional error label.

Yes, should add a new error label.

> 
> > +		goto error_free_adc_irq;
> > +
> > +	imx93_adc_config_ad_clk(adc);
> > +
> > +	ret = iio_device_register(indio_dev);
> > +	if (ret) {
> > +		dev_err_probe(dev, ret,
> > +			      "Failed to register this iio device.\n");
> > +		goto error_free_adc_irq;
> > +	}
> > +
> > +	pm_runtime_set_active(dev);
> > +	pm_runtime_set_autosuspend_delay(dev, 50);
> > +	pm_runtime_use_autosuspend(dev);
> > +	pm_runtime_enable(dev);
> > +
> > +	return 0;
> > +
> > +error_free_adc_irq:
> > +	imx93_adc_power_down(adc);
> > +	free_irq(adc->irq, adc);
> > +error_ipg_clk_disable:
> > +	clk_disable_unprepare(adc->ipg_clk);
> > +error_regulator_disable:
> > +	regulator_disable(adc->vref);
> > +
> > +	return ret;
> > +}
> > +
> > +static int imx93_adc_remove(struct platform_device *pdev) {
> > +	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
> > +	struct imx93_adc *adc = iio_priv(indio_dev);
> > +	struct device *dev = adc->dev;
> 
> As per reply to cover letter I don't understand logic by which we are definitely
> runtime resumed at this stage.
> 
> > +
> > +	pm_runtime_disable(dev);
> > +	pm_runtime_dont_use_autosuspend(dev);
> > +	pm_runtime_put_noidle(dev);
> 
> This is not balanced with a pm_runtime_get* so I think we underflow (which is
> protected against in runtime pm ref counting but not a nice thing to do
> deliberately).

Oh, yes, seems still need to call pm_runtime_get_sync() even we still in runtime resume state.

Best Regards
Haibo Chen
> 
> > +	iio_device_unregister(indio_dev);
> > +	imx93_adc_power_down(adc);
> > +	free_irq(adc->irq, adc);
> > +	clk_disable_unprepare(adc->ipg_clk);
> > +	regulator_disable(adc->vref);
> > +
> > +	return 0;
> > +}
> > +





[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux