root/arch/arm/mach-s3c24xx/mach-osiris-dvs.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. osiris_dvs_tps_setdvs
  2. is_dvs
  3. osiris_dvs_notify
  4. osiris_dvs_probe
  5. osiris_dvs_remove
  6. osiris_dvs_suspend
  7. osiris_dvs_resume

   1 // SPDX-License-Identifier: GPL-2.0
   2 //
   3 // Copyright (c) 2009 Simtec Electronics
   4 //      http://armlinux.simtec.co.uk/
   5 //      Ben Dooks <ben@simtec.co.uk>
   6 //
   7 // Simtec Osiris Dynamic Voltage Scaling support.
   8 
   9 #include <linux/kernel.h>
  10 #include <linux/module.h>
  11 #include <linux/platform_device.h>
  12 #include <linux/cpufreq.h>
  13 #include <linux/gpio.h>
  14 
  15 #include <linux/mfd/tps65010.h>
  16 
  17 #include <plat/cpu-freq.h>
  18 #include <mach/gpio-samsung.h>
  19 
  20 #define OSIRIS_GPIO_DVS S3C2410_GPB(5)
  21 
  22 static bool dvs_en;
  23 
  24 static void osiris_dvs_tps_setdvs(bool on)
  25 {
  26         unsigned vregs1 = 0, vdcdc2 = 0;
  27 
  28         if (!on) {
  29                 vdcdc2 = TPS_VCORE_DISCH | TPS_LP_COREOFF;
  30                 vregs1 = TPS_LDO1_OFF;  /* turn off in low-power mode */
  31         }
  32 
  33         dvs_en = on;
  34         vdcdc2 |= TPS_VCORE_1_3V | TPS_VCORE_LP_1_0V;
  35         vregs1 |= TPS_LDO2_ENABLE | TPS_LDO1_ENABLE;
  36 
  37         tps65010_config_vregs1(vregs1);
  38         tps65010_config_vdcdc2(vdcdc2);
  39 }
  40 
  41 static bool is_dvs(struct s3c_freq *f)
  42 {
  43         /* at the moment, we assume ARMCLK = HCLK => DVS */
  44         return f->armclk == f->hclk;
  45 }
  46 
  47 /* keep track of current state */
  48 static bool cur_dvs = false;
  49 
  50 static int osiris_dvs_notify(struct notifier_block *nb,
  51                               unsigned long val, void *data)
  52 {
  53         struct cpufreq_freqs *cf = data;
  54         struct s3c_cpufreq_freqs *freqs = to_s3c_cpufreq(cf);
  55         bool old_dvs = is_dvs(&freqs->old);
  56         bool new_dvs = is_dvs(&freqs->new);
  57         int ret = 0;
  58 
  59         if (!dvs_en)
  60                 return 0;
  61 
  62         printk(KERN_DEBUG "%s: old %ld,%ld new %ld,%ld\n", __func__,
  63                freqs->old.armclk, freqs->old.hclk,
  64                freqs->new.armclk, freqs->new.hclk);
  65 
  66         switch (val) {
  67         case CPUFREQ_PRECHANGE:
  68                 if ((old_dvs && !new_dvs) ||
  69                     (cur_dvs && !new_dvs)) {
  70                         pr_debug("%s: exiting dvs\n", __func__);
  71                         cur_dvs = false;
  72                         gpio_set_value(OSIRIS_GPIO_DVS, 1);
  73                 }
  74                 break;
  75         case CPUFREQ_POSTCHANGE:
  76                 if ((!old_dvs && new_dvs) ||
  77                     (!cur_dvs && new_dvs)) {
  78                         pr_debug("entering dvs\n");
  79                         cur_dvs = true;
  80                         gpio_set_value(OSIRIS_GPIO_DVS, 0);
  81                 }
  82                 break;
  83         }
  84 
  85         return ret;
  86 }
  87 
  88 static struct notifier_block osiris_dvs_nb = {
  89         .notifier_call  = osiris_dvs_notify,
  90 };
  91 
  92 static int osiris_dvs_probe(struct platform_device *pdev)
  93 {
  94         int ret;
  95 
  96         dev_info(&pdev->dev, "initialising\n");
  97 
  98         ret = gpio_request(OSIRIS_GPIO_DVS, "osiris-dvs");
  99         if (ret) {
 100                 dev_err(&pdev->dev, "cannot claim gpio\n");
 101                 goto err_nogpio;
 102         }
 103 
 104         /* start with dvs disabled */
 105         gpio_direction_output(OSIRIS_GPIO_DVS, 1);
 106 
 107         ret = cpufreq_register_notifier(&osiris_dvs_nb,
 108                                         CPUFREQ_TRANSITION_NOTIFIER);
 109         if (ret) {
 110                 dev_err(&pdev->dev, "failed to register with cpufreq\n");
 111                 goto err_nofreq;
 112         }
 113 
 114         osiris_dvs_tps_setdvs(true);
 115 
 116         return 0;
 117 
 118 err_nofreq:
 119         gpio_free(OSIRIS_GPIO_DVS);
 120 
 121 err_nogpio:
 122         return ret;
 123 }
 124 
 125 static int osiris_dvs_remove(struct platform_device *pdev)
 126 {
 127         dev_info(&pdev->dev, "exiting\n");
 128 
 129         /* disable any current dvs */
 130         gpio_set_value(OSIRIS_GPIO_DVS, 1);
 131         osiris_dvs_tps_setdvs(false);
 132 
 133         cpufreq_unregister_notifier(&osiris_dvs_nb,
 134                                     CPUFREQ_TRANSITION_NOTIFIER);
 135 
 136         gpio_free(OSIRIS_GPIO_DVS);
 137 
 138         return 0;
 139 }
 140 
 141 /* the CONFIG_PM block is so small, it isn't worth actually compiling it
 142  * out if the configuration isn't set. */
 143 
 144 static int osiris_dvs_suspend(struct device *dev)
 145 {
 146         gpio_set_value(OSIRIS_GPIO_DVS, 1);
 147         osiris_dvs_tps_setdvs(false);
 148         cur_dvs = false;
 149 
 150         return 0;
 151 }
 152 
 153 static int osiris_dvs_resume(struct device *dev)
 154 {
 155         osiris_dvs_tps_setdvs(true);
 156         return 0;
 157 }
 158 
 159 static const struct dev_pm_ops osiris_dvs_pm = {
 160         .suspend        = osiris_dvs_suspend,
 161         .resume         = osiris_dvs_resume,
 162 };
 163 
 164 static struct platform_driver osiris_dvs_driver = {
 165         .probe          = osiris_dvs_probe,
 166         .remove         = osiris_dvs_remove,
 167         .driver         = {
 168                 .name   = "osiris-dvs",
 169                 .pm     = &osiris_dvs_pm,
 170         },
 171 };
 172 
 173 module_platform_driver(osiris_dvs_driver);
 174 
 175 MODULE_DESCRIPTION("Simtec OSIRIS DVS support");
 176 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
 177 MODULE_LICENSE("GPL");
 178 MODULE_ALIAS("platform:osiris-dvs");

/* [<][>][^][v][top][bottom][index][help] */