]> Git Repo - linux.git/commitdiff
Merge tag 'pullreq_20170131' of https://git.kernel.org/pub/scm/linux/kernel/git/mzx...
authorRafael J. Wysocki <[email protected]>
Tue, 31 Jan 2017 12:18:06 +0000 (13:18 +0100)
committerRafael J. Wysocki <[email protected]>
Tue, 31 Jan 2017 12:18:06 +0000 (13:18 +0100)
Pull devfreq changes for v4.11 from MyungJoo Ham.

* tag 'pullreq_20170131' of https://git.kernel.org/pub/scm/linux/kernel/git/mzx/devfreq:
  PM / devfreq: Modify the device name as devfreq(X) for sysfs
  PM / devfreq: Simplify the sysfs name of devfreq-event device
  PM / devfreq: Remove unnecessary separate _remove_devfreq()
  PM / devfreq: Fix wrong trans_stat of passive devfreq device
  PM / devfreq: Fix available_governor sysfs
  PM / devfreq: exynos-ppmu: Show the registred device for ppmu device
  PM / devfreq: Fix the wrong description for userspace governor
  PM / devfreq: Fix the checkpatch warnings
  PM / devfreq: exynos-bus: Print the real clock rate of bus
  PM / devfreq: exynos-ppmu: Use the regmap interface to handle the registers
  PM / devfreq: exynos-bus: Add the detailed correlation for Exynos5433
  PM / devfreq: Don't delete sysfs group twice

Documentation/ABI/testing/sysfs-class-devfreq-event [new file with mode: 0644]
Documentation/devicetree/bindings/devfreq/exynos-bus.txt
drivers/devfreq/devfreq-event.c
drivers/devfreq/devfreq.c
drivers/devfreq/event/exynos-ppmu.c
drivers/devfreq/exynos-bus.c
drivers/devfreq/governor.h
drivers/devfreq/governor_passive.c
drivers/devfreq/governor_userspace.c
include/linux/devfreq.h

diff --git a/Documentation/ABI/testing/sysfs-class-devfreq-event b/Documentation/ABI/testing/sysfs-class-devfreq-event
new file mode 100644 (file)
index 0000000..ceaf0f6
--- /dev/null
@@ -0,0 +1,25 @@
+What:          /sys/class/devfreq-event/event(x)/
+Date:          January 2017
+Contact:       Chanwoo Choi <[email protected]>
+Description:
+               Provide a place in sysfs for the devfreq-event objects.
+               This allows accessing various devfreq-event specific variables.
+               The name of devfreq-event object denoted as 'event(x)' which
+               includes the unique number of 'x' for each devfreq-event object.
+
+What:          /sys/class/devfreq-event/event(x)/name
+Date:          January 2017
+Contact:       Chanwoo Choi <[email protected]>
+Description:
+               The /sys/class/devfreq-event/event(x)/name attribute contains
+               the name of the devfreq-event object. This attribute is
+               read-only.
+
+What:          /sys/class/devfreq-event/event(x)/enable_count
+Date:          January 2017
+Contact:       Chanwoo Choi <[email protected]>
+Description:
+               The /sys/class/devfreq-event/event(x)/enable_count attribute
+               contains the reference count to enable the devfreq-event
+               object. If the device is enabled, the value of attribute is
+               greater than zero.
index d3ec8e676b6bf306309b42bdd4678403a1682c82..d085ef90d27c1f8b82645177169f71c3eb42d00f 100644 (file)
@@ -123,6 +123,20 @@ Detailed correlation between sub-blocks and power line according to Exynos SoC:
                |--- FSYS
                |--- FSYS2
 
+- In case of Exynos5433, there is VDD_INT power line as following:
+       VDD_INT |--- G2D (parent device)
+               |--- MSCL
+               |--- GSCL
+               |--- JPEG
+               |--- MFC
+               |--- HEVC
+               |--- BUS0
+               |--- BUS1
+               |--- BUS2
+               |--- PERIS (Fixed clock rate)
+               |--- PERIC (Fixed clock rate)
+               |--- FSYS  (Fixed clock rate)
+
 Example1:
        Show the AXI buses of Exynos3250 SoC. Exynos3250 divides the buses to
        power line (regulator). The MIF (Memory Interface) AXI bus is used to
index 9aea2c7ecbe6ec3cba2802502ca54181df0f3935..8648b32ebc8906c123561eaca53af6e48f655a1a 100644 (file)
@@ -306,7 +306,7 @@ struct devfreq_event_dev *devfreq_event_add_edev(struct device *dev,
                                                struct devfreq_event_desc *desc)
 {
        struct devfreq_event_dev *edev;
-       static atomic_t event_no = ATOMIC_INIT(0);
+       static atomic_t event_no = ATOMIC_INIT(-1);
        int ret;
 
        if (!dev || !desc)
@@ -329,7 +329,7 @@ struct devfreq_event_dev *devfreq_event_add_edev(struct device *dev,
        edev->dev.class = devfreq_event_class;
        edev->dev.release = devfreq_event_release_edev;
 
-       dev_set_name(&edev->dev, "event.%d", atomic_inc_return(&event_no) - 1);
+       dev_set_name(&edev->dev, "event%d", atomic_inc_return(&event_no));
        ret = device_register(&edev->dev);
        if (ret < 0) {
                put_device(&edev->dev);
index 47206a21bb901f424c4e331c9db6eaedef69d93d..4aa72b5ed660edba50576080c6434b536ee43afb 100644 (file)
@@ -130,7 +130,7 @@ static void devfreq_set_freq_table(struct devfreq *devfreq)
  * @devfreq:   the devfreq instance
  * @freq:      the update target frequency
  */
-static int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
+int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
 {
        int lev, prev_lev, ret = 0;
        unsigned long cur_time;
@@ -166,6 +166,7 @@ out:
        devfreq->last_stat_updated = cur_time;
        return ret;
 }
+EXPORT_SYMBOL(devfreq_update_status);
 
 /**
  * find_devfreq_governor() - find devfreq governor from name
@@ -474,11 +475,15 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
 }
 
 /**
- * _remove_devfreq() - Remove devfreq from the list and release its resources.
- * @devfreq:   the devfreq struct
+ * devfreq_dev_release() - Callback for struct device to release the device.
+ * @dev:       the devfreq device
+ *
+ * Remove devfreq from the list and release its resources.
  */
-static void _remove_devfreq(struct devfreq *devfreq)
+static void devfreq_dev_release(struct device *dev)
 {
+       struct devfreq *devfreq = to_devfreq(dev);
+
        mutex_lock(&devfreq_list_lock);
        if (IS_ERR(find_device_devfreq(devfreq->dev.parent))) {
                mutex_unlock(&devfreq_list_lock);
@@ -499,19 +504,6 @@ static void _remove_devfreq(struct devfreq *devfreq)
        kfree(devfreq);
 }
 
-/**
- * devfreq_dev_release() - Callback for struct device to release the device.
- * @dev:       the devfreq device
- *
- * This calls _remove_devfreq() if _remove_devfreq() is not called.
- */
-static void devfreq_dev_release(struct device *dev)
-{
-       struct devfreq *devfreq = to_devfreq(dev);
-
-       _remove_devfreq(devfreq);
-}
-
 /**
  * devfreq_add_device() - Add devfreq feature to the device
  * @dev:       the device to add devfreq feature.
@@ -527,6 +519,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
 {
        struct devfreq *devfreq;
        struct devfreq_governor *governor;
+       static atomic_t devfreq_no = ATOMIC_INIT(-1);
        int err = 0;
 
        if (!dev || !profile || !governor_name) {
@@ -538,15 +531,14 @@ struct devfreq *devfreq_add_device(struct device *dev,
        devfreq = find_device_devfreq(dev);
        mutex_unlock(&devfreq_list_lock);
        if (!IS_ERR(devfreq)) {
-               dev_err(dev, "%s: Unable to create devfreq for the device. It already has one.\n", __func__);
+               dev_err(dev, "%s: Unable to create devfreq for the device.\n",
+                       __func__);
                err = -EINVAL;
                goto err_out;
        }
 
        devfreq = kzalloc(sizeof(struct devfreq), GFP_KERNEL);
        if (!devfreq) {
-               dev_err(dev, "%s: Unable to create devfreq for the device\n",
-                       __func__);
                err = -ENOMEM;
                goto err_out;
        }
@@ -569,18 +561,21 @@ struct devfreq *devfreq_add_device(struct device *dev,
                mutex_lock(&devfreq->lock);
        }
 
-       dev_set_name(&devfreq->dev, "%s", dev_name(dev));
+       dev_set_name(&devfreq->dev, "devfreq%d",
+                               atomic_inc_return(&devfreq_no));
        err = device_register(&devfreq->dev);
        if (err) {
                mutex_unlock(&devfreq->lock);
                goto err_out;
        }
 
-       devfreq->trans_table =  devm_kzalloc(&devfreq->dev, sizeof(unsigned int) *
+       devfreq->trans_table =  devm_kzalloc(&devfreq->dev,
+                                               sizeof(unsigned int) *
                                                devfreq->profile->max_state *
                                                devfreq->profile->max_state,
                                                GFP_KERNEL);
-       devfreq->time_in_state = devm_kzalloc(&devfreq->dev, sizeof(unsigned long) *
+       devfreq->time_in_state = devm_kzalloc(&devfreq->dev,
+                                               sizeof(unsigned long) *
                                                devfreq->profile->max_state,
                                                GFP_KERNEL);
        devfreq->last_stat_updated = jiffies;
@@ -939,6 +934,9 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
        if (df->governor == governor) {
                ret = 0;
                goto out;
+       } else if (df->governor->immutable || governor->immutable) {
+               ret = -EINVAL;
+               goto out;
        }
 
        if (df->governor) {
@@ -968,13 +966,33 @@ static ssize_t available_governors_show(struct device *d,
                                        struct device_attribute *attr,
                                        char *buf)
 {
-       struct devfreq_governor *tmp_governor;
+       struct devfreq *df = to_devfreq(d);
        ssize_t count = 0;
 
        mutex_lock(&devfreq_list_lock);
-       list_for_each_entry(tmp_governor, &devfreq_governor_list, node)
-               count += scnprintf(&buf[count], (PAGE_SIZE - count - 2),
-                                  "%s ", tmp_governor->name);
+
+       /*
+        * The devfreq with immutable governor (e.g., passive) shows
+        * only own governor.
+        */
+       if (df->governor->immutable) {
+               count = scnprintf(&buf[count], DEVFREQ_NAME_LEN,
+                                  "%s ", df->governor_name);
+       /*
+        * The devfreq device shows the registered governor except for
+        * immutable governors such as passive governor .
+        */
+       } else {
+               struct devfreq_governor *governor;
+
+               list_for_each_entry(governor, &devfreq_governor_list, node) {
+                       if (governor->immutable)
+                               continue;
+                       count += scnprintf(&buf[count], (PAGE_SIZE - count - 2),
+                                          "%s ", governor->name);
+               }
+       }
+
        mutex_unlock(&devfreq_list_lock);
 
        /* Truncate the trailing space */
@@ -995,7 +1013,7 @@ static ssize_t cur_freq_show(struct device *dev, struct device_attribute *attr,
 
        if (devfreq->profile->get_cur_freq &&
                !devfreq->profile->get_cur_freq(devfreq->dev.parent, &freq))
-                       return sprintf(buf, "%lu\n", freq);
+               return sprintf(buf, "%lu\n", freq);
 
        return sprintf(buf, "%lu\n", devfreq->previous_freq);
 }
index 107eb91a9415d26eb429bee2c47dc39ac132e648..9b7350935b73259828a897a7eea6d4fc9b2e4c4f 100644 (file)
 #include <linux/module.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/suspend.h>
 #include <linux/devfreq-event.h>
 
 #include "exynos-ppmu.h"
 
 struct exynos_ppmu_data {
-       void __iomem *base;
        struct clk *clk;
 };
 
@@ -33,6 +33,7 @@ struct exynos_ppmu {
        unsigned int num_events;
 
        struct device *dev;
+       struct regmap *regmap;
 
        struct exynos_ppmu_data ppmu;
 };
@@ -107,20 +108,28 @@ static int exynos_ppmu_find_ppmu_id(struct devfreq_event_dev *edev)
 static int exynos_ppmu_disable(struct devfreq_event_dev *edev)
 {
        struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
+       int ret;
        u32 pmnc;
 
        /* Disable all counters */
-       __raw_writel(PPMU_CCNT_MASK |
-                    PPMU_PMCNT0_MASK |
-                    PPMU_PMCNT1_MASK |
-                    PPMU_PMCNT2_MASK |
-                    PPMU_PMCNT3_MASK,
-                    info->ppmu.base + PPMU_CNTENC);
+       ret = regmap_write(info->regmap, PPMU_CNTENC,
+                               PPMU_CCNT_MASK |
+                               PPMU_PMCNT0_MASK |
+                               PPMU_PMCNT1_MASK |
+                               PPMU_PMCNT2_MASK |
+                               PPMU_PMCNT3_MASK);
+       if (ret < 0)
+               return ret;
 
        /* Disable PPMU */
-       pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC);
+       ret = regmap_read(info->regmap, PPMU_PMNC, &pmnc);
+       if (ret < 0)
+               return ret;
+
        pmnc &= ~PPMU_PMNC_ENABLE_MASK;
-       __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC);
+       ret = regmap_write(info->regmap, PPMU_PMNC, pmnc);
+       if (ret < 0)
+               return ret;
 
        return 0;
 }
@@ -129,29 +138,42 @@ static int exynos_ppmu_set_event(struct devfreq_event_dev *edev)
 {
        struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
        int id = exynos_ppmu_find_ppmu_id(edev);
+       int ret;
        u32 pmnc, cntens;
 
        if (id < 0)
                return id;
 
        /* Enable specific counter */
-       cntens = __raw_readl(info->ppmu.base + PPMU_CNTENS);
+       ret = regmap_read(info->regmap, PPMU_CNTENS, &cntens);
+       if (ret < 0)
+               return ret;
+
        cntens |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id));
-       __raw_writel(cntens, info->ppmu.base + PPMU_CNTENS);
+       ret = regmap_write(info->regmap, PPMU_CNTENS, cntens);
+       if (ret < 0)
+               return ret;
 
        /* Set the event of Read/Write data count  */
-       __raw_writel(PPMU_RO_DATA_CNT | PPMU_WO_DATA_CNT,
-                       info->ppmu.base + PPMU_BEVTxSEL(id));
+       ret = regmap_write(info->regmap, PPMU_BEVTxSEL(id),
+                               PPMU_RO_DATA_CNT | PPMU_WO_DATA_CNT);
+       if (ret < 0)
+               return ret;
 
        /* Reset cycle counter/performance counter and enable PPMU */
-       pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC);
+       ret = regmap_read(info->regmap, PPMU_PMNC, &pmnc);
+       if (ret < 0)
+               return ret;
+
        pmnc &= ~(PPMU_PMNC_ENABLE_MASK
                        | PPMU_PMNC_COUNTER_RESET_MASK
                        | PPMU_PMNC_CC_RESET_MASK);
        pmnc |= (PPMU_ENABLE << PPMU_PMNC_ENABLE_SHIFT);
        pmnc |= (PPMU_ENABLE << PPMU_PMNC_COUNTER_RESET_SHIFT);
        pmnc |= (PPMU_ENABLE << PPMU_PMNC_CC_RESET_SHIFT);
-       __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC);
+       ret = regmap_write(info->regmap, PPMU_PMNC, pmnc);
+       if (ret < 0)
+               return ret;
 
        return 0;
 }
@@ -161,40 +183,64 @@ static int exynos_ppmu_get_event(struct devfreq_event_dev *edev,
 {
        struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
        int id = exynos_ppmu_find_ppmu_id(edev);
-       u32 pmnc, cntenc;
+       unsigned int total_count, load_count;
+       unsigned int pmcnt3_high, pmcnt3_low;
+       unsigned int pmnc, cntenc;
+       int ret;
 
        if (id < 0)
                return -EINVAL;
 
        /* Disable PPMU */
-       pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC);
+       ret = regmap_read(info->regmap, PPMU_PMNC, &pmnc);
+       if (ret < 0)
+               return ret;
+
        pmnc &= ~PPMU_PMNC_ENABLE_MASK;
-       __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC);
+       ret = regmap_write(info->regmap, PPMU_PMNC, pmnc);
+       if (ret < 0)
+               return ret;
 
        /* Read cycle count */
-       edata->total_count = __raw_readl(info->ppmu.base + PPMU_CCNT);
+       ret = regmap_read(info->regmap, PPMU_CCNT, &total_count);
+       if (ret < 0)
+               return ret;
+       edata->total_count = total_count;
 
        /* Read performance count */
        switch (id) {
        case PPMU_PMNCNT0:
        case PPMU_PMNCNT1:
        case PPMU_PMNCNT2:
-               edata->load_count
-                       = __raw_readl(info->ppmu.base + PPMU_PMNCT(id));
+               ret = regmap_read(info->regmap, PPMU_PMNCT(id), &load_count);
+               if (ret < 0)
+                       return ret;
+               edata->load_count = load_count;
                break;
        case PPMU_PMNCNT3:
-               edata->load_count =
-                       ((__raw_readl(info->ppmu.base + PPMU_PMCNT3_HIGH) << 8)
-                       | __raw_readl(info->ppmu.base + PPMU_PMCNT3_LOW));
+               ret = regmap_read(info->regmap, PPMU_PMCNT3_HIGH, &pmcnt3_high);
+               if (ret < 0)
+                       return ret;
+
+               ret = regmap_read(info->regmap, PPMU_PMCNT3_LOW, &pmcnt3_low);
+               if (ret < 0)
+                       return ret;
+
+               edata->load_count = ((pmcnt3_high << 8) | pmcnt3_low);
                break;
        default:
                return -EINVAL;
        }
 
        /* Disable specific counter */
-       cntenc = __raw_readl(info->ppmu.base + PPMU_CNTENC);
+       ret = regmap_read(info->regmap, PPMU_CNTENC, &cntenc);
+       if (ret < 0)
+               return ret;
+
        cntenc |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id));
-       __raw_writel(cntenc, info->ppmu.base + PPMU_CNTENC);
+       ret = regmap_write(info->regmap, PPMU_CNTENC, cntenc);
+       if (ret < 0)
+               return ret;
 
        dev_dbg(&edev->dev, "%s (event: %ld/%ld)\n", edev->desc->name,
                                        edata->load_count, edata->total_count);
@@ -214,36 +260,93 @@ static const struct devfreq_event_ops exynos_ppmu_ops = {
 static int exynos_ppmu_v2_disable(struct devfreq_event_dev *edev)
 {
        struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
+       int ret;
        u32 pmnc, clear;
 
        /* Disable all counters */
        clear = (PPMU_CCNT_MASK | PPMU_PMCNT0_MASK | PPMU_PMCNT1_MASK
                | PPMU_PMCNT2_MASK | PPMU_PMCNT3_MASK);
+       ret = regmap_write(info->regmap, PPMU_V2_FLAG, clear);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_INTENC, clear);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_CNTENC, clear);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_CNT_RESET, clear);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_CIG_CFG0, 0x0);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_CIG_CFG1, 0x0);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_CIG_CFG2, 0x0);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_CIG_RESULT, 0x0);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_CNT_AUTO, 0x0);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_CH_EV0_TYPE, 0x0);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_CH_EV1_TYPE, 0x0);
+       if (ret < 0)
+               return ret;
 
-       __raw_writel(clear, info->ppmu.base + PPMU_V2_FLAG);
-       __raw_writel(clear, info->ppmu.base + PPMU_V2_INTENC);
-       __raw_writel(clear, info->ppmu.base + PPMU_V2_CNTENC);
-       __raw_writel(clear, info->ppmu.base + PPMU_V2_CNT_RESET);
-
-       __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_CFG0);
-       __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_CFG1);
-       __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_CFG2);
-       __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_RESULT);
-       __raw_writel(0x0, info->ppmu.base + PPMU_V2_CNT_AUTO);
-       __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV0_TYPE);
-       __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV1_TYPE);
-       __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV2_TYPE);
-       __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV3_TYPE);
-       __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_ID_V);
-       __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_ID_A);
-       __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_OTHERS_V);
-       __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_OTHERS_A);
-       __raw_writel(0x0, info->ppmu.base + PPMU_V2_INTERRUPT_RESET);
+       ret = regmap_write(info->regmap, PPMU_V2_CH_EV2_TYPE, 0x0);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_CH_EV3_TYPE, 0x0);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_SM_ID_V, 0x0);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_SM_ID_A, 0x0);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_SM_OTHERS_V, 0x0);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_SM_OTHERS_A, 0x0);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_INTERRUPT_RESET, 0x0);
+       if (ret < 0)
+               return ret;
 
        /* Disable PPMU */
-       pmnc = __raw_readl(info->ppmu.base + PPMU_V2_PMNC);
+       ret = regmap_read(info->regmap, PPMU_V2_PMNC, &pmnc);
+       if (ret < 0)
+               return ret;
+
        pmnc &= ~PPMU_PMNC_ENABLE_MASK;
-       __raw_writel(pmnc, info->ppmu.base + PPMU_V2_PMNC);
+       ret = regmap_write(info->regmap, PPMU_V2_PMNC, pmnc);
+       if (ret < 0)
+               return ret;
 
        return 0;
 }
@@ -251,30 +354,43 @@ static int exynos_ppmu_v2_disable(struct devfreq_event_dev *edev)
 static int exynos_ppmu_v2_set_event(struct devfreq_event_dev *edev)
 {
        struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
+       unsigned int pmnc, cntens;
        int id = exynos_ppmu_find_ppmu_id(edev);
-       u32 pmnc, cntens;
+       int ret;
 
        /* Enable all counters */
-       cntens = __raw_readl(info->ppmu.base + PPMU_V2_CNTENS);
+       ret = regmap_read(info->regmap, PPMU_V2_CNTENS, &cntens);
+       if (ret < 0)
+               return ret;
+
        cntens |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id));
-       __raw_writel(cntens, info->ppmu.base + PPMU_V2_CNTENS);
+       ret = regmap_write(info->regmap, PPMU_V2_CNTENS, cntens);
+       if (ret < 0)
+               return ret;
 
        /* Set the event of Read/Write data count  */
        switch (id) {
        case PPMU_PMNCNT0:
        case PPMU_PMNCNT1:
        case PPMU_PMNCNT2:
-               __raw_writel(PPMU_V2_RO_DATA_CNT | PPMU_V2_WO_DATA_CNT,
-                               info->ppmu.base + PPMU_V2_CH_EVx_TYPE(id));
+               ret = regmap_write(info->regmap, PPMU_V2_CH_EVx_TYPE(id),
+                               PPMU_V2_RO_DATA_CNT | PPMU_V2_WO_DATA_CNT);
+               if (ret < 0)
+                       return ret;
                break;
        case PPMU_PMNCNT3:
-               __raw_writel(PPMU_V2_EVT3_RW_DATA_CNT,
-                               info->ppmu.base + PPMU_V2_CH_EVx_TYPE(id));
+               ret = regmap_write(info->regmap, PPMU_V2_CH_EVx_TYPE(id),
+                               PPMU_V2_EVT3_RW_DATA_CNT);
+               if (ret < 0)
+                       return ret;
                break;
        }
 
        /* Reset cycle counter/performance counter and enable PPMU */
-       pmnc = __raw_readl(info->ppmu.base + PPMU_V2_PMNC);
+       ret = regmap_read(info->regmap, PPMU_V2_PMNC, &pmnc);
+       if (ret < 0)
+               return ret;
+
        pmnc &= ~(PPMU_PMNC_ENABLE_MASK
                        | PPMU_PMNC_COUNTER_RESET_MASK
                        | PPMU_PMNC_CC_RESET_MASK
@@ -284,7 +400,10 @@ static int exynos_ppmu_v2_set_event(struct devfreq_event_dev *edev)
        pmnc |= (PPMU_ENABLE << PPMU_PMNC_COUNTER_RESET_SHIFT);
        pmnc |= (PPMU_ENABLE << PPMU_PMNC_CC_RESET_SHIFT);
        pmnc |= (PPMU_V2_MODE_MANUAL << PPMU_V2_PMNC_START_MODE_SHIFT);
-       __raw_writel(pmnc, info->ppmu.base + PPMU_V2_PMNC);
+
+       ret = regmap_write(info->regmap, PPMU_V2_PMNC, pmnc);
+       if (ret < 0)
+               return ret;
 
        return 0;
 }
@@ -294,37 +413,61 @@ static int exynos_ppmu_v2_get_event(struct devfreq_event_dev *edev,
 {
        struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
        int id = exynos_ppmu_find_ppmu_id(edev);
-       u32 pmnc, cntenc;
-       u32 pmcnt_high, pmcnt_low;
-       u64 load_count = 0;
+       int ret;
+       unsigned int pmnc, cntenc;
+       unsigned int pmcnt_high, pmcnt_low;
+       unsigned int total_count, count;
+       unsigned long load_count = 0;
 
        /* Disable PPMU */
-       pmnc = __raw_readl(info->ppmu.base + PPMU_V2_PMNC);
+       ret = regmap_read(info->regmap, PPMU_V2_PMNC, &pmnc);
+       if (ret < 0)
+               return ret;
+
        pmnc &= ~PPMU_PMNC_ENABLE_MASK;
-       __raw_writel(pmnc, info->ppmu.base + PPMU_V2_PMNC);
+       ret = regmap_write(info->regmap, PPMU_V2_PMNC, pmnc);
+       if (ret < 0)
+               return ret;
 
        /* Read cycle count and performance count */
-       edata->total_count = __raw_readl(info->ppmu.base + PPMU_V2_CCNT);
+       ret = regmap_read(info->regmap, PPMU_V2_CCNT, &total_count);
+       if (ret < 0)
+               return ret;
+       edata->total_count = total_count;
 
        switch (id) {
        case PPMU_PMNCNT0:
        case PPMU_PMNCNT1:
        case PPMU_PMNCNT2:
-               load_count = __raw_readl(info->ppmu.base + PPMU_V2_PMNCT(id));
+               ret = regmap_read(info->regmap, PPMU_V2_PMNCT(id), &count);
+               if (ret < 0)
+                       return ret;
+               load_count = count;
                break;
        case PPMU_PMNCNT3:
-               pmcnt_high = __raw_readl(info->ppmu.base + PPMU_V2_PMCNT3_HIGH);
-               pmcnt_low = __raw_readl(info->ppmu.base + PPMU_V2_PMCNT3_LOW);
-               load_count = ((u64)((pmcnt_high & 0xff)) << 32)
-                          + (u64)pmcnt_low;
+               ret = regmap_read(info->regmap, PPMU_V2_PMCNT3_HIGH,
+                                               &pmcnt_high);
+               if (ret < 0)
+                       return ret;
+
+               ret = regmap_read(info->regmap, PPMU_V2_PMCNT3_LOW, &pmcnt_low);
+               if (ret < 0)
+                       return ret;
+
+               load_count = ((u64)((pmcnt_high & 0xff)) << 32)+ (u64)pmcnt_low;
                break;
        }
        edata->load_count = load_count;
 
        /* Disable all counters */
-       cntenc = __raw_readl(info->ppmu.base + PPMU_V2_CNTENC);
+       ret = regmap_read(info->regmap, PPMU_V2_CNTENC, &cntenc);
+       if (ret < 0)
+               return 0;
+
        cntenc |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id));
-       __raw_writel(cntenc, info->ppmu.base + PPMU_V2_CNTENC);
+       ret = regmap_write(info->regmap, PPMU_V2_CNTENC, cntenc);
+       if (ret < 0)
+               return ret;
 
        dev_dbg(&edev->dev, "%25s (load: %ld / %ld)\n", edev->desc->name,
                                        edata->load_count, edata->total_count);
@@ -411,10 +554,19 @@ static int of_get_devfreq_events(struct device_node *np,
        return 0;
 }
 
-static int exynos_ppmu_parse_dt(struct exynos_ppmu *info)
+static struct regmap_config exynos_ppmu_regmap_config = {
+       .reg_bits = 32,
+       .val_bits = 32,
+       .reg_stride = 4,
+};
+
+static int exynos_ppmu_parse_dt(struct platform_device *pdev,
+                               struct exynos_ppmu *info)
 {
        struct device *dev = info->dev;
        struct device_node *np = dev->of_node;
+       struct resource *res;
+       void __iomem *base;
        int ret = 0;
 
        if (!np) {
@@ -423,10 +575,17 @@ static int exynos_ppmu_parse_dt(struct exynos_ppmu *info)
        }
 
        /* Maps the memory mapped IO to control PPMU register */
-       info->ppmu.base = of_iomap(np, 0);
-       if (IS_ERR_OR_NULL(info->ppmu.base)) {
-               dev_err(dev, "failed to map memory region\n");
-               return -ENOMEM;
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       exynos_ppmu_regmap_config.max_register = resource_size(res) - 4;
+       info->regmap = devm_regmap_init_mmio(dev, base,
+                                       &exynos_ppmu_regmap_config);
+       if (IS_ERR(info->regmap)) {
+               dev_err(dev, "failed to initialize regmap\n");
+               return PTR_ERR(info->regmap);
        }
 
        info->ppmu.clk = devm_clk_get(dev, "ppmu");
@@ -438,15 +597,10 @@ static int exynos_ppmu_parse_dt(struct exynos_ppmu *info)
        ret = of_get_devfreq_events(np, info);
        if (ret < 0) {
                dev_err(dev, "failed to parse exynos ppmu dt node\n");
-               goto err;
+               return ret;
        }
 
        return 0;
-
-err:
-       iounmap(info->ppmu.base);
-
-       return ret;
 }
 
 static int exynos_ppmu_probe(struct platform_device *pdev)
@@ -463,7 +617,7 @@ static int exynos_ppmu_probe(struct platform_device *pdev)
        info->dev = &pdev->dev;
 
        /* Parse dt data to get resource */
-       ret = exynos_ppmu_parse_dt(info);
+       ret = exynos_ppmu_parse_dt(pdev, info);
        if (ret < 0) {
                dev_err(&pdev->dev,
                        "failed to parse devicetree for resource\n");
@@ -476,8 +630,7 @@ static int exynos_ppmu_probe(struct platform_device *pdev)
        if (!info->edev) {
                dev_err(&pdev->dev,
                        "failed to allocate memory devfreq-event devices\n");
-               ret = -ENOMEM;
-               goto err;
+               return -ENOMEM;
        }
        edev = info->edev;
        platform_set_drvdata(pdev, info);
@@ -488,17 +641,16 @@ static int exynos_ppmu_probe(struct platform_device *pdev)
                        ret = PTR_ERR(edev[i]);
                        dev_err(&pdev->dev,
                                "failed to add devfreq-event device\n");
-                       goto err;
+                       return PTR_ERR(edev[i]);
                }
+
+               pr_info("exynos-ppmu: new PPMU device registered %s (%s)\n",
+                       dev_name(&pdev->dev), desc[i].name);
        }
 
        clk_prepare_enable(info->ppmu.clk);
 
        return 0;
-err:
-       iounmap(info->ppmu.base);
-
-       return ret;
 }
 
 static int exynos_ppmu_remove(struct platform_device *pdev)
@@ -506,7 +658,6 @@ static int exynos_ppmu_remove(struct platform_device *pdev)
        struct exynos_ppmu *info = platform_get_drvdata(pdev);
 
        clk_disable_unprepare(info->ppmu.clk);
-       iounmap(info->ppmu.base);
 
        return 0;
 }
index 9af86f46fbec0fc0779e4cf211c16227b804510d..e0d1f4ac174062196585daf59c4416fcd5463cea 100644 (file)
@@ -147,8 +147,8 @@ static int exynos_bus_target(struct device *dev, unsigned long *freq, u32 flags)
        }
        bus->curr_freq = new_freq;
 
-       dev_dbg(dev, "Set the frequency of bus (%lukHz -> %lukHz)\n",
-                       old_freq/1000, new_freq/1000);
+       dev_dbg(dev, "Set the frequency of bus (%luHz -> %luHz, %luHz)\n",
+                       old_freq, new_freq, clk_get_rate(bus->clk));
 out:
        mutex_unlock(&bus->lock);
 
@@ -241,8 +241,8 @@ static int exynos_bus_passive_target(struct device *dev, unsigned long *freq,
        *freq = new_freq;
        bus->curr_freq = new_freq;
 
-       dev_dbg(dev, "Set the frequency of bus (%lukHz -> %lukHz)\n",
-                       old_freq/1000, new_freq/1000);
+       dev_dbg(dev, "Set the frequency of bus (%luHz -> %luHz, %luHz)\n",
+                       old_freq, new_freq, clk_get_rate(bus->clk));
 out:
        mutex_unlock(&bus->lock);
 
index fad7d63219786387e191ea4130bf5a0b7b37001b..71576b8bdfeff2f5fc5a1e5108eef21c35396949 100644 (file)
@@ -38,4 +38,6 @@ extern void devfreq_interval_update(struct devfreq *devfreq,
 extern int devfreq_add_governor(struct devfreq_governor *governor);
 extern int devfreq_remove_governor(struct devfreq_governor *governor);
 
+extern int devfreq_update_status(struct devfreq *devfreq, unsigned long freq);
+
 #endif /* _GOVERNOR_H */
index 9ef46e2592c45616cb59471c7cb2698155b56b7e..5be96b2249e72a1e8cf1280f1c5a10bdfd54a6d3 100644 (file)
@@ -112,6 +112,11 @@ static int update_devfreq_passive(struct devfreq *devfreq, unsigned long freq)
        if (ret < 0)
                goto out;
 
+       if (devfreq->profile->freq_table
+               && (devfreq_update_status(devfreq, freq)))
+               dev_err(&devfreq->dev,
+                       "Couldn't update frequency transition information.\n");
+
        devfreq->previous_freq = freq;
 
 out:
@@ -179,6 +184,7 @@ static int devfreq_passive_event_handler(struct devfreq *devfreq,
 
 static struct devfreq_governor devfreq_passive = {
        .name = "passive",
+       .immutable = 1,
        .get_target_freq = devfreq_passive_get_target_freq,
        .event_handler = devfreq_passive_event_handler,
 };
index 35de6e83c1febedd99f8c155e374b5d4f8bb5202..176976068bcd1552d0a625ea47ebdf72812b4c6b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/devfreq/governor_simpleondemand.c
+ *  linux/drivers/devfreq/governor_userspace.c
  *
  *  Copyright (C) 2011 Samsung Electronics
  *     MyungJoo Ham <[email protected]>
@@ -50,7 +50,6 @@ static ssize_t store_freq(struct device *dev, struct device_attribute *attr,
        unsigned long wanted;
        int err = 0;
 
-
        mutex_lock(&devfreq->lock);
        data = devfreq->data;
 
@@ -112,7 +111,13 @@ out:
 
 static void userspace_exit(struct devfreq *devfreq)
 {
-       sysfs_remove_group(&devfreq->dev.kobj, &dev_attr_group);
+       /*
+        * Remove the sysfs entry, unless this is being called after
+        * device_del(), which should have done this already via kobject_del().
+        */
+       if (devfreq->dev.kobj.sd)
+               sysfs_remove_group(&devfreq->dev.kobj, &dev_attr_group);
+
        kfree(devfreq->data);
        devfreq->data = NULL;
 }
index 2de4e2eea180d133898980f87c659f86a7fb922b..e0acb0e5243b49552480ed8cfac2d037226f4304 100644 (file)
@@ -104,6 +104,8 @@ struct devfreq_dev_profile {
  * struct devfreq_governor - Devfreq policy governor
  * @node:              list node - contains registered devfreq governors
  * @name:              Governor's name
+ * @immutable:         Immutable flag for governor. If the value is 1,
+ *                     this govenror is never changeable to other governor.
  * @get_target_freq:   Returns desired operating frequency for the device.
  *                     Basically, get_target_freq will run
  *                     devfreq_dev_profile.get_dev_status() to get the
@@ -121,6 +123,7 @@ struct devfreq_governor {
        struct list_head node;
 
        const char name[DEVFREQ_NAME_LEN];
+       const unsigned int immutable;
        int (*get_target_freq)(struct devfreq *this, unsigned long *freq);
        int (*event_handler)(struct devfreq *devfreq,
                                unsigned int event, void *data);
This page took 0.133305 seconds and 4 git commands to generate.