Subject: [PATCH 04/10] ARM: OMAP: omap_device: register to the per-device PM QoS framework

From: [email-masked] (Rajendra Nayak)
Date: Wed, 20 Jun 2012 16:11:24 +0530

On Thursday 14 June 2012 08:35 PM, Jean Pihet wrote:
> Implement the devices wake-up latency constraints using the global
> device PM QoS notification handler which applies the constraints to the
> underlying layer by calling the corresponding function at hwmod level.
>
> Tested on OMAP3 Beagleboard and OMAP4 Pandaboard in RET/OFF using wake-up
> latency constraints on MPU, CORE and PER.
>
> Signed-off-by: Jean Pihet<[email-masked]>
> Reviewed-by: Kevin Hilman<[email-masked]>
> [paul at pwsan.com: modified to work with omap_devices with large numbers of
>   hwmods; moved code to mach-omap2/omap_device.c; added documentation; use
>   notifier return codes]
> Signed-off-by: Paul Walmsley<[email-masked]>
> ---
>   arch/arm/plat-omap/omap_device.c |   81 +++++++++++++++++++++++++++++++++++++-
>   1 files changed, 80 insertions(+), 1 deletions(-)
>
> diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
> index c490240..241705b 100644
> --- a/arch/arm/plat-omap/omap_device.c
> +++ b/arch/arm/plat-omap/omap_device.c
> @@ -3,6 +3,7 @@
>    * omap_device implementation
>    *
>    * Copyright (C) 2009-2010 Nokia Corporation
> + * Copyright (C) 2011 Texas Instruments, Inc.

2012?

>    * Paul Walmsley, Kevin Hilman
>    *
>    * Developed in collaboration with (alphabetical order): Benoit
> @@ -89,6 +90,7 @@
>   #include<linux/pm_runtime.h>
>   #include<linux/of.h>
>   #include<linux/notifier.h>
> +#include<linux/pm_qos.h>
>
>   #include<plat/omap_device.h>
>   #include<plat/omap_hwmod.h>
> @@ -401,6 +403,72 @@ static int _omap_device_notifier_call(struct notifier_block *nb,
>   	return NOTIFY_DONE;
>   }
>
> +/**
> + * _omap_device_pm_qos_handler - interface to the per-device PM QoS framework
> + * @nb: pointer to omap_device_pm_qos_nb (not used)
> + * @new_value: new maximum wakeup latency constraint for @req->dev (in us)
> + * @req: struct dev_pm_qos_request * passed by the Linux PM QoS code
> + *
> + * Called by the Linux core device PM QoS code to alter the maximum
> + * wakeup latency constraint on a device.  If the underlying device is
> + * an omap_device, then this code will pass the constraint on to the
> + * underlying hwmods.  Returns -EINVAL if this code can't handle the
> + * constraint for some reason, or passes along the return code from the
> + * hwmod wakeup latency constraint functions.
> + */
> +static int _omap_device_pm_qos_handler(struct notifier_block *nb,
> +				       unsigned long new_value,
> +				       void *req)
> +{
> +	struct omap_device *od;
> +	struct omap_hwmod *oh;
> +	struct platform_device *pdev;
> +	struct dev_pm_qos_request *dev_pm_qos_req = req;
> +	int ret = NOTIFY_OK;
> +	int r, i;
> +
> +	pr_debug("OMAP PM constraints: req at 0x%p, new_value=%lu\n",
> +		 req, new_value);
> +
> +	/* Look for the platform device for the constraint target device */
> +	pdev = to_platform_device(dev_pm_qos_req->dev);
> +
> +	/* Try to catch non platform devices */
> +	if (pdev->name == NULL) {

Is this a safe way to catch non platform devices?

regards,
Rajendra
> +		pr_err("%s: Error: platform device for device %s not valid\n",
> +		       __func__, dev_name(dev_pm_qos_req->dev));
> +		return NOTIFY_DONE;
> +	}
> +
> +	/* Find the associated omap_device for dev */
> +	od = to_omap_device(pdev);
> +	if (od == NULL) {
> +		pr_err("%s: Error: no omap_device for device %s\n",
> +		       __func__, dev_name(dev_pm_qos_req->dev));
> +		return NOTIFY_DONE;
> +	}
> +
> +	pr_debug("OMAP PM constraints: req at 0x%p, dev=0x%p, new_value=%lu\n",
> +		 req, dev_pm_qos_req->dev, new_value);
> +
> +	for (i = 0; i<  od->hwmods_cnt; i++) {
> +		oh = od->hwmods[i];
> +		if (new_value == PM_QOS_DEV_LAT_DEFAULT_VALUE)
> +			r = omap_hwmod_remove_wakeuplat_constraint(
> +							oh,
> +							dev_pm_qos_req);
> +		else
> +			r = omap_hwmod_set_wakeuplat_constraint(
> +							oh,
> +							dev_pm_qos_req,
> +							new_value);
> +
> +		if (!r)
> +			ret = NOTIFY_BAD;
> +	}
> +
> +	return ret;
> +}
>
>   /* Public functions for use by core code */
>
> @@ -1115,13 +1183,24 @@ int omap_device_enable_clocks(struct omap_device *od)
>   	return 0;
>   }
>
> +static struct notifier_block omap_device_pm_qos_nb = {
> +	.notifier_call = _omap_device_pm_qos_handler,
> +};
> +
>   static struct notifier_block platform_nb = {
>   	.notifier_call = _omap_device_notifier_call,
>   };
>
>   static int __init omap_device_init(void)
>   {
> +	int ret;
> +
>   	bus_register_notifier(&platform_bus_type,&platform_nb);
> -	return 0;
> +
> +	ret = dev_pm_qos_add_global_notifier(&omap_device_pm_qos_nb);
> +	if (ret)
> +		pr_err("omap_device: cannot add global notifier for dev PM QoS\n");
> +
> +	return ret;
>   }
>   core_initcall(omap_device_init);