linux/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * linux/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
   4 *
   5 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
   6 *              http://www.samsung.com/
   7 */
   8
   9#include <linux/clk.h>
  10#include <linux/err.h>
  11#include <linux/platform_device.h>
  12#include <linux/pm_runtime.h>
  13#include "s5p_mfc_common.h"
  14#include "s5p_mfc_debug.h"
  15#include "s5p_mfc_pm.h"
  16
  17static struct s5p_mfc_pm *pm;
  18static struct s5p_mfc_dev *p_dev;
  19static atomic_t clk_ref;
  20
  21int s5p_mfc_init_pm(struct s5p_mfc_dev *dev)
  22{
  23        int i;
  24
  25        pm = &dev->pm;
  26        p_dev = dev;
  27
  28        pm->num_clocks = dev->variant->num_clocks;
  29        pm->clk_names = dev->variant->clk_names;
  30        pm->device = &dev->plat_dev->dev;
  31        pm->clock_gate = NULL;
  32
  33        /* clock control */
  34        for (i = 0; i < pm->num_clocks; i++) {
  35                pm->clocks[i] = devm_clk_get(pm->device, pm->clk_names[i]);
  36                if (IS_ERR(pm->clocks[i])) {
  37                        /* additional clocks are optional */
  38                        if (i && PTR_ERR(pm->clocks[i]) == -ENOENT) {
  39                                pm->clocks[i] = NULL;
  40                                continue;
  41                        }
  42                        mfc_err("Failed to get clock: %s\n",
  43                                pm->clk_names[i]);
  44                        return PTR_ERR(pm->clocks[i]);
  45                }
  46        }
  47
  48        if (dev->variant->use_clock_gating)
  49                pm->clock_gate = pm->clocks[0];
  50
  51        pm_runtime_enable(pm->device);
  52        atomic_set(&clk_ref, 0);
  53        return 0;
  54}
  55
  56void s5p_mfc_final_pm(struct s5p_mfc_dev *dev)
  57{
  58        pm_runtime_disable(pm->device);
  59}
  60
  61int s5p_mfc_clock_on(void)
  62{
  63        atomic_inc(&clk_ref);
  64        mfc_debug(3, "+ %d\n", atomic_read(&clk_ref));
  65
  66        return clk_enable(pm->clock_gate);
  67}
  68
  69void s5p_mfc_clock_off(void)
  70{
  71        atomic_dec(&clk_ref);
  72        mfc_debug(3, "- %d\n", atomic_read(&clk_ref));
  73
  74        clk_disable(pm->clock_gate);
  75}
  76
  77int s5p_mfc_power_on(void)
  78{
  79        int i, ret = 0;
  80
  81        ret = pm_runtime_resume_and_get(pm->device);
  82        if (ret < 0)
  83                return ret;
  84
  85        /* clock control */
  86        for (i = 0; i < pm->num_clocks; i++) {
  87                ret = clk_prepare_enable(pm->clocks[i]);
  88                if (ret < 0) {
  89                        mfc_err("clock prepare failed for clock: %s\n",
  90                                pm->clk_names[i]);
  91                        i++;
  92                        goto err;
  93                }
  94        }
  95
  96        /* prepare for software clock gating */
  97        clk_disable(pm->clock_gate);
  98
  99        return 0;
 100err:
 101        while (--i > 0)
 102                clk_disable_unprepare(pm->clocks[i]);
 103        pm_runtime_put(pm->device);
 104        return ret;
 105}
 106
 107int s5p_mfc_power_off(void)
 108{
 109        int i;
 110
 111        /* finish software clock gating */
 112        clk_enable(pm->clock_gate);
 113
 114        for (i = 0; i < pm->num_clocks; i++)
 115                clk_disable_unprepare(pm->clocks[i]);
 116
 117        return pm_runtime_put_sync(pm->device);
 118}
 119
 120