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