mach-osiris-dvs.c (3844B)
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 <linux/soc/samsung/s3c-cpu-freq.h> 18#include "gpio-samsung.h" 19 20#define OSIRIS_GPIO_DVS S3C2410_GPB(5) 21 22static bool dvs_en; 23 24static 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 41static 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 */ 48static bool cur_dvs = false; 49 50static 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 88static struct notifier_block osiris_dvs_nb = { 89 .notifier_call = osiris_dvs_notify, 90}; 91 92static 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 118err_nofreq: 119 gpio_free(OSIRIS_GPIO_DVS); 120 121err_nogpio: 122 return ret; 123} 124 125static 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 144static 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 153static int osiris_dvs_resume(struct device *dev) 154{ 155 osiris_dvs_tps_setdvs(true); 156 return 0; 157} 158 159static const struct dev_pm_ops osiris_dvs_pm = { 160 .suspend = osiris_dvs_suspend, 161 .resume = osiris_dvs_resume, 162}; 163 164static 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 173module_platform_driver(osiris_dvs_driver); 174 175MODULE_DESCRIPTION("Simtec OSIRIS DVS support"); 176MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); 177MODULE_LICENSE("GPL"); 178MODULE_ALIAS("platform:osiris-dvs");