Skip to content

Commit

Permalink
Merge branch 'pm-devfreq'
Browse files Browse the repository at this point in the history
* pm-devfreq:
  PM / devfreq: remove checks for CONFIG_EXYNOS_ASV
  PM / devfreq: exynos5: Use devm_devfreq_* function using device resource management
  PM / devfreq: exynos4: Use devm_devfreq_* function using device resource management
  PM / devfreq: Add devm_devfreq_{register,unregister}_opp_notfier function
  PM / devfreq: Add resource-managed function for devfreq device
  PM / devfreq: Fix devfreq_remove_device() to improve the sequence of resource free
  PM / devfreq: exynos: make more PPMU code common
  PM / devfreq: exynos5: introduce struct busfreq_ppmu_data
  PM / devfreq: exynos4: introduce struct busfreq_ppmu_data
  PM / devfreq: exynos4: use common PPMU code
  PM / devfreq: exynos5: Add CONFIG_PM_OPP dependency to fix probe fail
  PM / devfreq: exynos5: Use SIMPLE_DEV_PM_OPS macro
  PM / devfreq: exynos4: Add CONFIG_PM_OPP dependency to fix probe fail
  PM / devfreq: exynos4: Use SIMPLE_DEV_PM_OPS macro
  PM / devfreq: exynos4: Fix bug of resource leak and code clean on probe()
  • Loading branch information
Rafael J. Wysocki committed Jun 3, 2014
2 parents cd0c5bd + 6392bfd commit 42a0928
Show file tree
Hide file tree
Showing 8 changed files with 317 additions and 267 deletions.
5 changes: 3 additions & 2 deletions drivers/devfreq/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -70,19 +70,20 @@ config ARM_EXYNOS4_BUS_DEVFREQ
depends on (CPU_EXYNOS4210 || SOC_EXYNOS4212 || SOC_EXYNOS4412) && !ARCH_MULTIPLATFORM
select ARCH_HAS_OPP
select DEVFREQ_GOV_SIMPLE_ONDEMAND
select PM_OPP
help
This adds the DEVFREQ driver for Exynos4210 memory bus (vdd_int)
and Exynos4212/4412 memory interface and bus (vdd_mif + vdd_int).
It reads PPMU counters of memory controllers and adjusts
the operating frequencies and voltages with OPP support.
To operate with optimal voltages, ASV support is required
(CONFIG_EXYNOS_ASV).
This does not yet operate with optimal voltages.

config ARM_EXYNOS5_BUS_DEVFREQ
bool "ARM Exynos5250 Bus DEVFREQ Driver"
depends on SOC_EXYNOS5250
select ARCH_HAS_OPP
select DEVFREQ_GOV_SIMPLE_ONDEMAND
select PM_OPP
help
This adds the DEVFREQ driver for Exynos5250 bus interface (vdd_int).
It reads PPMU counters of memory controllers and adjusts the
Expand Down
125 changes: 115 additions & 10 deletions drivers/devfreq/devfreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
* @devfreq: the devfreq struct
* @skip: skip calling device_unregister().
*/
static void _remove_devfreq(struct devfreq *devfreq, bool skip)
static void _remove_devfreq(struct devfreq *devfreq)
{
mutex_lock(&devfreq_list_lock);
if (IS_ERR(find_device_devfreq(devfreq->dev.parent))) {
Expand All @@ -412,11 +412,6 @@ static void _remove_devfreq(struct devfreq *devfreq, bool skip)
if (devfreq->profile->exit)
devfreq->profile->exit(devfreq->dev.parent);

if (!skip && get_device(&devfreq->dev)) {
device_unregister(&devfreq->dev);
put_device(&devfreq->dev);
}

mutex_destroy(&devfreq->lock);
kfree(devfreq);
}
Expand All @@ -426,14 +421,12 @@ static void _remove_devfreq(struct devfreq *devfreq, bool skip)
* @dev: the devfreq device
*
* This calls _remove_devfreq() if _remove_devfreq() is not called.
* Note that devfreq_dev_release() could be called by _remove_devfreq() as
* well as by others unregistering the device.
*/
static void devfreq_dev_release(struct device *dev)
{
struct devfreq *devfreq = to_devfreq(dev);

_remove_devfreq(devfreq, true);
_remove_devfreq(devfreq);
}

/**
Expand Down Expand Up @@ -544,12 +537,76 @@ int devfreq_remove_device(struct devfreq *devfreq)
if (!devfreq)
return -EINVAL;

_remove_devfreq(devfreq, false);
device_unregister(&devfreq->dev);
put_device(&devfreq->dev);

return 0;
}
EXPORT_SYMBOL(devfreq_remove_device);

static int devm_devfreq_dev_match(struct device *dev, void *res, void *data)
{
struct devfreq **r = res;

if (WARN_ON(!r || !*r))
return 0;

return *r == data;
}

static void devm_devfreq_dev_release(struct device *dev, void *res)
{
devfreq_remove_device(*(struct devfreq **)res);
}

/**
* devm_devfreq_add_device() - Resource-managed devfreq_add_device()
* @dev: the device to add devfreq feature.
* @profile: device-specific profile to run devfreq.
* @governor_name: name of the policy to choose frequency.
* @data: private data for the governor. The devfreq framework does not
* touch this value.
*
* This function manages automatically the memory of devfreq device using device
* resource management and simplify the free operation for memory of devfreq
* device.
*/
struct devfreq *devm_devfreq_add_device(struct device *dev,
struct devfreq_dev_profile *profile,
const char *governor_name,
void *data)
{
struct devfreq **ptr, *devfreq;

ptr = devres_alloc(devm_devfreq_dev_release, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return ERR_PTR(-ENOMEM);

devfreq = devfreq_add_device(dev, profile, governor_name, data);
if (IS_ERR(devfreq)) {
devres_free(ptr);
return ERR_PTR(-ENOMEM);
}

*ptr = devfreq;
devres_add(dev, ptr);

return devfreq;
}
EXPORT_SYMBOL(devm_devfreq_add_device);

/**
* devm_devfreq_remove_device() - Resource-managed devfreq_remove_device()
* @dev: the device to add devfreq feature.
* @devfreq: the devfreq instance to be removed
*/
void devm_devfreq_remove_device(struct device *dev, struct devfreq *devfreq)
{
WARN_ON(devres_release(dev, devm_devfreq_dev_release,
devm_devfreq_dev_match, devfreq));
}
EXPORT_SYMBOL(devm_devfreq_remove_device);

/**
* devfreq_suspend_device() - Suspend devfreq of a device.
* @devfreq: the devfreq instance to be suspended
Expand Down Expand Up @@ -1112,6 +1169,54 @@ int devfreq_unregister_opp_notifier(struct device *dev, struct devfreq *devfreq)
return ret;
}

static void devm_devfreq_opp_release(struct device *dev, void *res)
{
devfreq_unregister_opp_notifier(dev, *(struct devfreq **)res);
}

/**
* devm_ devfreq_register_opp_notifier()
* - Resource-managed devfreq_register_opp_notifier()
* @dev: The devfreq user device. (parent of devfreq)
* @devfreq: The devfreq object.
*/
int devm_devfreq_register_opp_notifier(struct device *dev,
struct devfreq *devfreq)
{
struct devfreq **ptr;
int ret;

ptr = devres_alloc(devm_devfreq_opp_release, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return -ENOMEM;

ret = devfreq_register_opp_notifier(dev, devfreq);
if (ret) {
devres_free(ptr);
return ret;
}

*ptr = devfreq;
devres_add(dev, ptr);

return 0;
}
EXPORT_SYMBOL(devm_devfreq_register_opp_notifier);

/**
* devm_devfreq_unregister_opp_notifier()
* - Resource-managed devfreq_unregister_opp_notifier()
* @dev: The devfreq user device. (parent of devfreq)
* @devfreq: The devfreq object.
*/
void devm_devfreq_unregister_opp_notifier(struct device *dev,
struct devfreq *devfreq)
{
WARN_ON(devres_release(dev, devm_devfreq_opp_release,
devm_devfreq_dev_match, devfreq));
}
EXPORT_SYMBOL(devm_devfreq_unregister_opp_notifier);

MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
MODULE_DESCRIPTION("devfreq class support");
MODULE_LICENSE("GPL");
2 changes: 1 addition & 1 deletion drivers/devfreq/exynos/Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Exynos DEVFREQ Drivers
obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ) += exynos4_bus.o
obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ) += exynos_ppmu.o exynos4_bus.o
obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ) += exynos_ppmu.o exynos5_bus.o
Loading

0 comments on commit 42a0928

Please sign in to comment.