diff mbox series

[v3,2/5] i2c: nvidia-gpu: add runtime pm support

Message ID 20190522183142.11061-3-ajayg@nvidia.com (mailing list archive)
State Superseded
Headers show
Series usb: typec: ucsi: ccg: add runtime pm support | expand

Commit Message

Ajay Gupta May 22, 2019, 6:31 p.m. UTC
From: Ajay Gupta <ajayg@nvidia.com>

Enable runtime pm support with autosuspend delay of three second.
This is to make sure I2C client device Cypress CCGx has completed
all transaction.

Signed-off-by: Ajay Gupta <ajayg@nvidia.com>
---
Changes from v1->v2:
	- Added __maybe_unused in gpu_i2c_suspend to avoid
	warning when CONFIG_PM is disabled. 

 drivers/i2c/busses/i2c-nvidia-gpu.c | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

Comments

Wolfram Sang May 25, 2019, 7:56 p.m. UTC | #1
> @@ -211,6 +212,8 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
>  		goto exit;
>  	}
>  
> +	pm_runtime_mark_last_busy(i2cd->dev);
> +	pm_runtime_put_autosuspend(i2cd->dev);
>  	return i;
>  exit:
>  	if (send_stop) {
> @@ -218,6 +221,8 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
>  		if (status2 < 0)
>  			dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
>  	}
> +	pm_runtime_mark_last_busy(i2cd->dev);
> +	pm_runtime_put_autosuspend(i2cd->dev);

Maybe another worthwhile refactorization possible here? The exit code
path and 'all good' code path look very similar. This can be done
incrementally, though. I think for now it is okay.

> +static __maybe_unused int gpu_i2c_suspend(struct device *dev)
> +{
> +	return 0;
> +}

Why do we need this?
Ajay Gupta May 28, 2019, 2:25 p.m. UTC | #2
Hi Wolfram,

> -----Original Message-----
> From: linux-usb-owner@vger.kernel.org <linux-usb-owner@vger.kernel.org>
> On Behalf Of Wolfram Sang
> Sent: Saturday, May 25, 2019 12:57 PM
> To: Ajay Gupta <ajaykuee@gmail.com>
> Cc: heikki.krogerus@linux.intel.com; linux-usb@vger.kernel.org; linux-
> i2c@vger.kernel.org; Ajay Gupta <ajayg@nvidia.com>
> Subject: Re: [PATCH v3 2/5] i2c: nvidia-gpu: add runtime pm support
> 
> 
> > @@ -211,6 +212,8 @@ static int gpu_i2c_master_xfer(struct i2c_adapter
> *adap,
> >  		goto exit;
> >  	}
> >
> > +	pm_runtime_mark_last_busy(i2cd->dev);
> > +	pm_runtime_put_autosuspend(i2cd->dev);
> >  	return i;
> >  exit:
> >  	if (send_stop) {
> > @@ -218,6 +221,8 @@ static int gpu_i2c_master_xfer(struct i2c_adapter
> *adap,
> >  		if (status2 < 0)
> >  			dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
> >  	}
> > +	pm_runtime_mark_last_busy(i2cd->dev);
> > +	pm_runtime_put_autosuspend(i2cd->dev);
> 
> Maybe another worthwhile refactorization possible here? The exit code path
> and 'all good' code path look very similar. 
> This can be done incrementally, though. I think for now it is okay.
Thanks for suggestion. Yes , it is possible to refactor a bit further here.
 
> > +static __maybe_unused int gpu_i2c_suspend(struct device *dev) {
> > +	return 0;
> > +}
> 
> Why do we need this?
I2C function of PCI bus remains in D0 (lspci output) without this function. 

Following document also seems to insist on this.
" For this to work, the device's driver has to provide a 
pm->runtime_suspend() callback "

Documentation/power/pci.txt 
"First, a PCI device is put into a low-power state, or suspended, with the help
of pm_schedule_suspend() or pm_runtime_suspend() which for PCI devices call
pci_pm_runtime_suspend() to do the actual job.  For this to work, the device's
driver has to provide a pm->runtime_suspend() callback (see below), which is
run by pci_pm_runtime_suspend() as the first action. If the driver's callback
returns successfully, the device's standard configuration registers are saved,
the device is prepared to generate wakeup signals and, finally, it is put into
the target low-power state."

Thanks
Ajay
> nvpublic
Ajay Gupta May 31, 2019, 7:42 p.m. UTC | #3
Hi Wolfram,

> > -----Original Message-----
> > From: linux-usb-owner@vger.kernel.org <linux-usb-
> owner@vger.kernel.org>
> > On Behalf Of Wolfram Sang
> > Sent: Saturday, May 25, 2019 12:57 PM
> > To: Ajay Gupta <ajaykuee@gmail.com>
> > Cc: heikki.krogerus@linux.intel.com; linux-usb@vger.kernel.org; linux-
> > i2c@vger.kernel.org; Ajay Gupta <ajayg@nvidia.com>
> > Subject: Re: [PATCH v3 2/5] i2c: nvidia-gpu: add runtime pm support
> >
> >
> > > @@ -211,6 +212,8 @@ static int gpu_i2c_master_xfer(struct i2c_adapter
> > *adap,
> > >  		goto exit;
> > >  	}
> > >
> > > +	pm_runtime_mark_last_busy(i2cd->dev);
> > > +	pm_runtime_put_autosuspend(i2cd->dev);
> > >  	return i;
> > >  exit:
> > >  	if (send_stop) {
> > > @@ -218,6 +221,8 @@ static int gpu_i2c_master_xfer(struct i2c_adapter
> > *adap,
> > >  		if (status2 < 0)
> > >  			dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
> > >  	}
> > > +	pm_runtime_mark_last_busy(i2cd->dev);
> > > +	pm_runtime_put_autosuspend(i2cd->dev);
> >
> > Maybe another worthwhile refactorization possible here? The exit code
> path
> > and 'all good' code path look very similar.
> > This can be done incrementally, though. I think for now it is okay.
> Thanks for suggestion. Yes , it is possible to refactor a bit further here.
> 
> > > +static __maybe_unused int gpu_i2c_suspend(struct device *dev) {
> > > +	return 0;
> > > +}
> >
> > Why do we need this?
> I2C function of PCI bus remains in D0 (lspci output) without this function.

Do you still see any issue with gpu_i2c_suspend()?

Thanks
Ajay
> nvpublic
> 
> Following document also seems to insist on this.
> " For this to work, the device's driver has to provide a
> pm->runtime_suspend() callback "
> 
> Documentation/power/pci.txt
> "First, a PCI device is put into a low-power state, or suspended, with the help
> of pm_schedule_suspend() or pm_runtime_suspend() which for PCI devices
> call
> pci_pm_runtime_suspend() to do the actual job.  For this to work, the
> device's
> driver has to provide a pm->runtime_suspend() callback (see below), which
> is
> run by pci_pm_runtime_suspend() as the first action. If the driver's callback
> returns successfully, the device's standard configuration registers are saved,
> the device is prepared to generate wakeup signals and, finally, it is put into
> the target low-power state."
> 
> Thanks
> Ajay
> > nvpublic
diff mbox series

Patch

diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c b/drivers/i2c/busses/i2c-nvidia-gpu.c
index 2d9561ec2320..28fee85135ac 100644
--- a/drivers/i2c/busses/i2c-nvidia-gpu.c
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -176,6 +176,7 @@  static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
 	 * The controller supports maximum 4 byte read due to known
 	 * limitation of sending STOP after every read.
 	 */
+	pm_runtime_get_sync(i2cd->dev);
 	for (i = 0; i < num; i++) {
 		if (msgs[i].flags & I2C_M_RD) {
 			/* program client address before starting read */
@@ -211,6 +212,8 @@  static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
 		goto exit;
 	}
 
+	pm_runtime_mark_last_busy(i2cd->dev);
+	pm_runtime_put_autosuspend(i2cd->dev);
 	return i;
 exit:
 	if (send_stop) {
@@ -218,6 +221,8 @@  static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
 		if (status2 < 0)
 			dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
 	}
+	pm_runtime_mark_last_busy(i2cd->dev);
+	pm_runtime_put_autosuspend(i2cd->dev);
 	return status;
 }
 
@@ -337,6 +342,11 @@  static int gpu_i2c_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 		goto del_adapter;
 	}
 
+	pm_runtime_set_autosuspend_delay(&pdev->dev, 3000);
+	pm_runtime_use_autosuspend(&pdev->dev);
+	pm_runtime_put_autosuspend(&pdev->dev);
+	pm_runtime_allow(&pdev->dev);
+
 	return 0;
 
 del_adapter:
@@ -350,10 +360,16 @@  static void gpu_i2c_remove(struct pci_dev *pdev)
 {
 	struct gpu_i2c_dev *i2cd = dev_get_drvdata(&pdev->dev);
 
+	pm_runtime_get_noresume(i2cd->dev);
 	i2c_del_adapter(&i2cd->adapter);
 	pci_free_irq_vectors(pdev);
 }
 
+static __maybe_unused int gpu_i2c_suspend(struct device *dev)
+{
+	return 0;
+}
+
 static __maybe_unused int gpu_i2c_resume(struct device *dev)
 {
 	struct gpu_i2c_dev *i2cd = dev_get_drvdata(dev);
@@ -362,7 +378,8 @@  static __maybe_unused int gpu_i2c_resume(struct device *dev)
 	return 0;
 }
 
-static UNIVERSAL_DEV_PM_OPS(gpu_i2c_driver_pm, NULL, gpu_i2c_resume, NULL);
+static UNIVERSAL_DEV_PM_OPS(gpu_i2c_driver_pm, gpu_i2c_suspend, gpu_i2c_resume,
+			    NULL);
 
 static struct pci_driver gpu_i2c_driver = {
 	.name		= "nvidia-gpu",