1eb982001SEduardo Valentin /* 2eb982001SEduardo Valentin * TI Bandgap temperature sensor driver 3eb982001SEduardo Valentin * 4eb982001SEduardo Valentin * Copyright (C) 2011-2012 Texas Instruments Incorporated - http://www.ti.com/ 5eb982001SEduardo Valentin * Author: J Keerthy <j-keerthy@ti.com> 6eb982001SEduardo Valentin * Author: Moiz Sonasath <m-sonasath@ti.com> 7eb982001SEduardo Valentin * Couple of fixes, DT and MFD adaptation: 8eb982001SEduardo Valentin * Eduardo Valentin <eduardo.valentin@ti.com> 9eb982001SEduardo Valentin * 10eb982001SEduardo Valentin * This program is free software; you can redistribute it and/or 11eb982001SEduardo Valentin * modify it under the terms of the GNU General Public License 12eb982001SEduardo Valentin * version 2 as published by the Free Software Foundation. 13eb982001SEduardo Valentin * 14eb982001SEduardo Valentin * This program is distributed in the hope that it will be useful, but 15eb982001SEduardo Valentin * WITHOUT ANY WARRANTY; without even the implied warranty of 16eb982001SEduardo Valentin * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17eb982001SEduardo Valentin * General Public License for more details. 18eb982001SEduardo Valentin * 19eb982001SEduardo Valentin * You should have received a copy of the GNU General Public License 20eb982001SEduardo Valentin * along with this program; if not, write to the Free Software 21eb982001SEduardo Valentin * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 22eb982001SEduardo Valentin * 02110-1301 USA 23eb982001SEduardo Valentin * 24eb982001SEduardo Valentin */ 25eb982001SEduardo Valentin 26eb982001SEduardo Valentin #include <linux/module.h> 27eb982001SEduardo Valentin #include <linux/export.h> 28eb982001SEduardo Valentin #include <linux/init.h> 29eb982001SEduardo Valentin #include <linux/kernel.h> 30eb982001SEduardo Valentin #include <linux/interrupt.h> 31eb982001SEduardo Valentin #include <linux/clk.h> 32eb982001SEduardo Valentin #include <linux/gpio.h> 33eb982001SEduardo Valentin #include <linux/platform_device.h> 34eb982001SEduardo Valentin #include <linux/err.h> 35eb982001SEduardo Valentin #include <linux/types.h> 36eb982001SEduardo Valentin #include <linux/spinlock.h> 37eb982001SEduardo Valentin #include <linux/reboot.h> 38eb982001SEduardo Valentin #include <linux/of_device.h> 39eb982001SEduardo Valentin #include <linux/of_platform.h> 40eb982001SEduardo Valentin #include <linux/of_irq.h> 4157d16171SEduardo Valentin #include <linux/of_gpio.h> 42eb982001SEduardo Valentin #include <linux/io.h> 43eb982001SEduardo Valentin 44eb982001SEduardo Valentin #include "ti-bandgap.h" 45eb982001SEduardo Valentin 46eb982001SEduardo Valentin /*** Helper functions to access registers and their bitfields ***/ 47eb982001SEduardo Valentin 48eb982001SEduardo Valentin /** 49eb982001SEduardo Valentin * ti_bandgap_readl() - simple read helper function 50eb982001SEduardo Valentin * @bgp: pointer to ti_bandgap structure 51eb982001SEduardo Valentin * @reg: desired register (offset) to be read 52eb982001SEduardo Valentin * 53eb982001SEduardo Valentin * Helper function to read bandgap registers. It uses the io remapped area. 54eb982001SEduardo Valentin * Return: the register value. 55eb982001SEduardo Valentin */ 56eb982001SEduardo Valentin static u32 ti_bandgap_readl(struct ti_bandgap *bgp, u32 reg) 57eb982001SEduardo Valentin { 58eb982001SEduardo Valentin return readl(bgp->base + reg); 59eb982001SEduardo Valentin } 60eb982001SEduardo Valentin 61eb982001SEduardo Valentin /** 62eb982001SEduardo Valentin * ti_bandgap_writel() - simple write helper function 63eb982001SEduardo Valentin * @bgp: pointer to ti_bandgap structure 64eb982001SEduardo Valentin * @val: desired register value to be written 65eb982001SEduardo Valentin * @reg: desired register (offset) to be written 66eb982001SEduardo Valentin * 67eb982001SEduardo Valentin * Helper function to write bandgap registers. It uses the io remapped area. 68eb982001SEduardo Valentin */ 69eb982001SEduardo Valentin static void ti_bandgap_writel(struct ti_bandgap *bgp, u32 val, u32 reg) 70eb982001SEduardo Valentin { 71eb982001SEduardo Valentin writel(val, bgp->base + reg); 72eb982001SEduardo Valentin } 73eb982001SEduardo Valentin 74eb982001SEduardo Valentin /** 75eb982001SEduardo Valentin * DOC: macro to update bits. 76eb982001SEduardo Valentin * 77eb982001SEduardo Valentin * RMW_BITS() - used to read, modify and update bandgap bitfields. 78eb982001SEduardo Valentin * The value passed will be shifted. 79eb982001SEduardo Valentin */ 80eb982001SEduardo Valentin #define RMW_BITS(bgp, id, reg, mask, val) \ 81eb982001SEduardo Valentin do { \ 82eb982001SEduardo Valentin struct temp_sensor_registers *t; \ 83eb982001SEduardo Valentin u32 r; \ 84eb982001SEduardo Valentin \ 85eb982001SEduardo Valentin t = bgp->conf->sensors[(id)].registers; \ 86eb982001SEduardo Valentin r = ti_bandgap_readl(bgp, t->reg); \ 87eb982001SEduardo Valentin r &= ~t->mask; \ 88eb982001SEduardo Valentin r |= (val) << __ffs(t->mask); \ 89eb982001SEduardo Valentin ti_bandgap_writel(bgp, r, t->reg); \ 90eb982001SEduardo Valentin } while (0) 91eb982001SEduardo Valentin 92eb982001SEduardo Valentin /*** Basic helper functions ***/ 93eb982001SEduardo Valentin 94eb982001SEduardo Valentin /** 95eb982001SEduardo Valentin * ti_bandgap_power() - controls the power state of a bandgap device 96eb982001SEduardo Valentin * @bgp: pointer to ti_bandgap structure 97eb982001SEduardo Valentin * @on: desired power state (1 - on, 0 - off) 98eb982001SEduardo Valentin * 99eb982001SEduardo Valentin * Used to power on/off a bandgap device instance. Only used on those 100eb982001SEduardo Valentin * that features tempsoff bit. 101eb982001SEduardo Valentin * 102eb982001SEduardo Valentin * Return: 0 on success, -ENOTSUPP if tempsoff is not supported. 103eb982001SEduardo Valentin */ 104eb982001SEduardo Valentin static int ti_bandgap_power(struct ti_bandgap *bgp, bool on) 105eb982001SEduardo Valentin { 106eb982001SEduardo Valentin int i, ret = 0; 107eb982001SEduardo Valentin 108eb982001SEduardo Valentin if (!TI_BANDGAP_HAS(bgp, POWER_SWITCH)) { 109eb982001SEduardo Valentin ret = -ENOTSUPP; 110eb982001SEduardo Valentin goto exit; 111eb982001SEduardo Valentin } 112eb982001SEduardo Valentin 113eb982001SEduardo Valentin for (i = 0; i < bgp->conf->sensor_count; i++) 114eb982001SEduardo Valentin /* active on 0 */ 115eb982001SEduardo Valentin RMW_BITS(bgp, i, temp_sensor_ctrl, bgap_tempsoff_mask, !on); 116eb982001SEduardo Valentin 117eb982001SEduardo Valentin exit: 118eb982001SEduardo Valentin return ret; 119eb982001SEduardo Valentin } 120eb982001SEduardo Valentin 121eb982001SEduardo Valentin /** 12279010636SKeerthy * ti_errata814_bandgap_read_temp() - helper function to read dra7 sensor temperature 12379010636SKeerthy * @bgp: pointer to ti_bandgap structure 12479010636SKeerthy * @reg: desired register (offset) to be read 12579010636SKeerthy * 12679010636SKeerthy * Function to read dra7 bandgap sensor temperature. This is done separately 12779010636SKeerthy * so as to workaround the errata "Bandgap Temperature read Dtemp can be 12879010636SKeerthy * corrupted" - Errata ID: i814". 12979010636SKeerthy * Read accesses to registers listed below can be corrupted due to incorrect 13079010636SKeerthy * resynchronization between clock domains. 13179010636SKeerthy * Read access to registers below can be corrupted : 13279010636SKeerthy * CTRL_CORE_DTEMP_MPU/GPU/CORE/DSPEVE/IVA_n (n = 0 to 4) 13379010636SKeerthy * CTRL_CORE_TEMP_SENSOR_MPU/GPU/CORE/DSPEVE/IVA_n 13479010636SKeerthy * 13579010636SKeerthy * Return: the register value. 13679010636SKeerthy */ 13779010636SKeerthy static u32 ti_errata814_bandgap_read_temp(struct ti_bandgap *bgp, u32 reg) 13879010636SKeerthy { 13979010636SKeerthy u32 val1, val2; 14079010636SKeerthy 14179010636SKeerthy val1 = ti_bandgap_readl(bgp, reg); 14279010636SKeerthy val2 = ti_bandgap_readl(bgp, reg); 14379010636SKeerthy 14479010636SKeerthy /* If both times we read the same value then that is right */ 14579010636SKeerthy if (val1 == val2) 14679010636SKeerthy return val1; 14779010636SKeerthy 14879010636SKeerthy /* if val1 and val2 are different read it third time */ 14979010636SKeerthy return ti_bandgap_readl(bgp, reg); 15079010636SKeerthy } 15179010636SKeerthy 15279010636SKeerthy /** 153eb982001SEduardo Valentin * ti_bandgap_read_temp() - helper function to read sensor temperature 154eb982001SEduardo Valentin * @bgp: pointer to ti_bandgap structure 155eb982001SEduardo Valentin * @id: bandgap sensor id 156eb982001SEduardo Valentin * 157eb982001SEduardo Valentin * Function to concentrate the steps to read sensor temperature register. 158eb982001SEduardo Valentin * This function is desired because, depending on bandgap device version, 159eb982001SEduardo Valentin * it might be needed to freeze the bandgap state machine, before fetching 160eb982001SEduardo Valentin * the register value. 161eb982001SEduardo Valentin * 162eb982001SEduardo Valentin * Return: temperature in ADC values. 163eb982001SEduardo Valentin */ 164eb982001SEduardo Valentin static u32 ti_bandgap_read_temp(struct ti_bandgap *bgp, int id) 165eb982001SEduardo Valentin { 166eb982001SEduardo Valentin struct temp_sensor_registers *tsr; 167eb982001SEduardo Valentin u32 temp, reg; 168eb982001SEduardo Valentin 169eb982001SEduardo Valentin tsr = bgp->conf->sensors[id].registers; 170eb982001SEduardo Valentin reg = tsr->temp_sensor_ctrl; 171eb982001SEduardo Valentin 172eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, FREEZE_BIT)) { 173eb982001SEduardo Valentin RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 1); 174eb982001SEduardo Valentin /* 175eb982001SEduardo Valentin * In case we cannot read from cur_dtemp / dtemp_0, 176eb982001SEduardo Valentin * then we read from the last valid temp read 177eb982001SEduardo Valentin */ 178eb982001SEduardo Valentin reg = tsr->ctrl_dtemp_1; 179eb982001SEduardo Valentin } 180eb982001SEduardo Valentin 181eb982001SEduardo Valentin /* read temperature */ 18279010636SKeerthy if (TI_BANDGAP_HAS(bgp, ERRATA_814)) 18379010636SKeerthy temp = ti_errata814_bandgap_read_temp(bgp, reg); 18479010636SKeerthy else 185eb982001SEduardo Valentin temp = ti_bandgap_readl(bgp, reg); 18679010636SKeerthy 187eb982001SEduardo Valentin temp &= tsr->bgap_dtemp_mask; 188eb982001SEduardo Valentin 189eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, FREEZE_BIT)) 190eb982001SEduardo Valentin RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 0); 191eb982001SEduardo Valentin 192eb982001SEduardo Valentin return temp; 193eb982001SEduardo Valentin } 194eb982001SEduardo Valentin 195eb982001SEduardo Valentin /*** IRQ handlers ***/ 196eb982001SEduardo Valentin 197eb982001SEduardo Valentin /** 198eb982001SEduardo Valentin * ti_bandgap_talert_irq_handler() - handles Temperature alert IRQs 199eb982001SEduardo Valentin * @irq: IRQ number 200eb982001SEduardo Valentin * @data: private data (struct ti_bandgap *) 201eb982001SEduardo Valentin * 202eb982001SEduardo Valentin * This is the Talert handler. Use it only if bandgap device features 203eb982001SEduardo Valentin * HAS(TALERT). This handler goes over all sensors and checks their 204eb982001SEduardo Valentin * conditions and acts accordingly. In case there are events pending, 205eb982001SEduardo Valentin * it will reset the event mask to wait for the opposite event (next event). 206eb982001SEduardo Valentin * Every time there is a new event, it will be reported to thermal layer. 207eb982001SEduardo Valentin * 208eb982001SEduardo Valentin * Return: IRQ_HANDLED 209eb982001SEduardo Valentin */ 210eb982001SEduardo Valentin static irqreturn_t ti_bandgap_talert_irq_handler(int irq, void *data) 211eb982001SEduardo Valentin { 212eb982001SEduardo Valentin struct ti_bandgap *bgp = data; 213eb982001SEduardo Valentin struct temp_sensor_registers *tsr; 214eb982001SEduardo Valentin u32 t_hot = 0, t_cold = 0, ctrl; 215eb982001SEduardo Valentin int i; 216eb982001SEduardo Valentin 217eb982001SEduardo Valentin spin_lock(&bgp->lock); 218eb982001SEduardo Valentin for (i = 0; i < bgp->conf->sensor_count; i++) { 219eb982001SEduardo Valentin tsr = bgp->conf->sensors[i].registers; 220eb982001SEduardo Valentin ctrl = ti_bandgap_readl(bgp, tsr->bgap_status); 221eb982001SEduardo Valentin 222eb982001SEduardo Valentin /* Read the status of t_hot */ 223eb982001SEduardo Valentin t_hot = ctrl & tsr->status_hot_mask; 224eb982001SEduardo Valentin 225eb982001SEduardo Valentin /* Read the status of t_cold */ 226eb982001SEduardo Valentin t_cold = ctrl & tsr->status_cold_mask; 227eb982001SEduardo Valentin 228eb982001SEduardo Valentin if (!t_cold && !t_hot) 229eb982001SEduardo Valentin continue; 230eb982001SEduardo Valentin 231eb982001SEduardo Valentin ctrl = ti_bandgap_readl(bgp, tsr->bgap_mask_ctrl); 232eb982001SEduardo Valentin /* 233eb982001SEduardo Valentin * One TALERT interrupt: Two sources 234eb982001SEduardo Valentin * If the interrupt is due to t_hot then mask t_hot and 235eb982001SEduardo Valentin * and unmask t_cold else mask t_cold and unmask t_hot 236eb982001SEduardo Valentin */ 237eb982001SEduardo Valentin if (t_hot) { 238eb982001SEduardo Valentin ctrl &= ~tsr->mask_hot_mask; 239eb982001SEduardo Valentin ctrl |= tsr->mask_cold_mask; 240eb982001SEduardo Valentin } else if (t_cold) { 241eb982001SEduardo Valentin ctrl &= ~tsr->mask_cold_mask; 242eb982001SEduardo Valentin ctrl |= tsr->mask_hot_mask; 243eb982001SEduardo Valentin } 244eb982001SEduardo Valentin 245eb982001SEduardo Valentin ti_bandgap_writel(bgp, ctrl, tsr->bgap_mask_ctrl); 246eb982001SEduardo Valentin 247eb982001SEduardo Valentin dev_dbg(bgp->dev, 248eb982001SEduardo Valentin "%s: IRQ from %s sensor: hotevent %d coldevent %d\n", 249eb982001SEduardo Valentin __func__, bgp->conf->sensors[i].domain, 250eb982001SEduardo Valentin t_hot, t_cold); 251eb982001SEduardo Valentin 252eb982001SEduardo Valentin /* report temperature to whom may concern */ 253eb982001SEduardo Valentin if (bgp->conf->report_temperature) 254eb982001SEduardo Valentin bgp->conf->report_temperature(bgp, i); 255eb982001SEduardo Valentin } 256eb982001SEduardo Valentin spin_unlock(&bgp->lock); 257eb982001SEduardo Valentin 258eb982001SEduardo Valentin return IRQ_HANDLED; 259eb982001SEduardo Valentin } 260eb982001SEduardo Valentin 261eb982001SEduardo Valentin /** 262eb982001SEduardo Valentin * ti_bandgap_tshut_irq_handler() - handles Temperature shutdown signal 263eb982001SEduardo Valentin * @irq: IRQ number 264eb982001SEduardo Valentin * @data: private data (unused) 265eb982001SEduardo Valentin * 266eb982001SEduardo Valentin * This is the Tshut handler. Use it only if bandgap device features 267eb982001SEduardo Valentin * HAS(TSHUT). If any sensor fires the Tshut signal, we simply shutdown 268eb982001SEduardo Valentin * the system. 269eb982001SEduardo Valentin * 270eb982001SEduardo Valentin * Return: IRQ_HANDLED 271eb982001SEduardo Valentin */ 272eb982001SEduardo Valentin static irqreturn_t ti_bandgap_tshut_irq_handler(int irq, void *data) 273eb982001SEduardo Valentin { 274eb982001SEduardo Valentin pr_emerg("%s: TSHUT temperature reached. Needs shut down...\n", 275eb982001SEduardo Valentin __func__); 276eb982001SEduardo Valentin 277eb982001SEduardo Valentin orderly_poweroff(true); 278eb982001SEduardo Valentin 279eb982001SEduardo Valentin return IRQ_HANDLED; 280eb982001SEduardo Valentin } 281eb982001SEduardo Valentin 282eb982001SEduardo Valentin /*** Helper functions which manipulate conversion ADC <-> mi Celsius ***/ 283eb982001SEduardo Valentin 284eb982001SEduardo Valentin /** 285eb982001SEduardo Valentin * ti_bandgap_adc_to_mcelsius() - converts an ADC value to mCelsius scale 286eb982001SEduardo Valentin * @bgp: struct ti_bandgap pointer 287eb982001SEduardo Valentin * @adc_val: value in ADC representation 288eb982001SEduardo Valentin * @t: address where to write the resulting temperature in mCelsius 289eb982001SEduardo Valentin * 290eb982001SEduardo Valentin * Simple conversion from ADC representation to mCelsius. In case the ADC value 291eb982001SEduardo Valentin * is out of the ADC conv table range, it returns -ERANGE, 0 on success. 292eb982001SEduardo Valentin * The conversion table is indexed by the ADC values. 293eb982001SEduardo Valentin * 294eb982001SEduardo Valentin * Return: 0 if conversion was successful, else -ERANGE in case the @adc_val 295eb982001SEduardo Valentin * argument is out of the ADC conv table range. 296eb982001SEduardo Valentin */ 297eb982001SEduardo Valentin static 298eb982001SEduardo Valentin int ti_bandgap_adc_to_mcelsius(struct ti_bandgap *bgp, int adc_val, int *t) 299eb982001SEduardo Valentin { 300eb982001SEduardo Valentin const struct ti_bandgap_data *conf = bgp->conf; 301eb982001SEduardo Valentin int ret = 0; 302eb982001SEduardo Valentin 303eb982001SEduardo Valentin /* look up for temperature in the table and return the temperature */ 304eb982001SEduardo Valentin if (adc_val < conf->adc_start_val || adc_val > conf->adc_end_val) { 305eb982001SEduardo Valentin ret = -ERANGE; 306eb982001SEduardo Valentin goto exit; 307eb982001SEduardo Valentin } 308eb982001SEduardo Valentin 309eb982001SEduardo Valentin *t = bgp->conf->conv_table[adc_val - conf->adc_start_val]; 310eb982001SEduardo Valentin 311eb982001SEduardo Valentin exit: 312eb982001SEduardo Valentin return ret; 313eb982001SEduardo Valentin } 314eb982001SEduardo Valentin 315eb982001SEduardo Valentin /** 316eb982001SEduardo Valentin * ti_bandgap_mcelsius_to_adc() - converts a mCelsius value to ADC scale 317eb982001SEduardo Valentin * @bgp: struct ti_bandgap pointer 318eb982001SEduardo Valentin * @temp: value in mCelsius 319eb982001SEduardo Valentin * @adc: address where to write the resulting temperature in ADC representation 320eb982001SEduardo Valentin * 321eb982001SEduardo Valentin * Simple conversion from mCelsius to ADC values. In case the temp value 322eb982001SEduardo Valentin * is out of the ADC conv table range, it returns -ERANGE, 0 on success. 323eb982001SEduardo Valentin * The conversion table is indexed by the ADC values. 324eb982001SEduardo Valentin * 325eb982001SEduardo Valentin * Return: 0 if conversion was successful, else -ERANGE in case the @temp 326eb982001SEduardo Valentin * argument is out of the ADC conv table range. 327eb982001SEduardo Valentin */ 328eb982001SEduardo Valentin static 329eb982001SEduardo Valentin int ti_bandgap_mcelsius_to_adc(struct ti_bandgap *bgp, long temp, int *adc) 330eb982001SEduardo Valentin { 331eb982001SEduardo Valentin const struct ti_bandgap_data *conf = bgp->conf; 332eb982001SEduardo Valentin const int *conv_table = bgp->conf->conv_table; 333eb982001SEduardo Valentin int high, low, mid, ret = 0; 334eb982001SEduardo Valentin 335eb982001SEduardo Valentin low = 0; 336eb982001SEduardo Valentin high = conf->adc_end_val - conf->adc_start_val; 337eb982001SEduardo Valentin mid = (high + low) / 2; 338eb982001SEduardo Valentin 339eb982001SEduardo Valentin if (temp < conv_table[low] || temp > conv_table[high]) { 340eb982001SEduardo Valentin ret = -ERANGE; 341eb982001SEduardo Valentin goto exit; 342eb982001SEduardo Valentin } 343eb982001SEduardo Valentin 344eb982001SEduardo Valentin while (low < high) { 345eb982001SEduardo Valentin if (temp < conv_table[mid]) 346eb982001SEduardo Valentin high = mid - 1; 347eb982001SEduardo Valentin else 348eb982001SEduardo Valentin low = mid + 1; 349eb982001SEduardo Valentin mid = (low + high) / 2; 350eb982001SEduardo Valentin } 351eb982001SEduardo Valentin 352eb982001SEduardo Valentin *adc = conf->adc_start_val + low; 353eb982001SEduardo Valentin 354eb982001SEduardo Valentin exit: 355eb982001SEduardo Valentin return ret; 356eb982001SEduardo Valentin } 357eb982001SEduardo Valentin 358eb982001SEduardo Valentin /** 359eb982001SEduardo Valentin * ti_bandgap_add_hyst() - add hysteresis (in mCelsius) to an ADC value 360eb982001SEduardo Valentin * @bgp: struct ti_bandgap pointer 361eb982001SEduardo Valentin * @adc_val: temperature value in ADC representation 362eb982001SEduardo Valentin * @hyst_val: hysteresis value in mCelsius 363eb982001SEduardo Valentin * @sum: address where to write the resulting temperature (in ADC scale) 364eb982001SEduardo Valentin * 365eb982001SEduardo Valentin * Adds an hysteresis value (in mCelsius) to a ADC temperature value. 366eb982001SEduardo Valentin * 367eb982001SEduardo Valentin * Return: 0 on success, -ERANGE otherwise. 368eb982001SEduardo Valentin */ 369eb982001SEduardo Valentin static 370eb982001SEduardo Valentin int ti_bandgap_add_hyst(struct ti_bandgap *bgp, int adc_val, int hyst_val, 371eb982001SEduardo Valentin u32 *sum) 372eb982001SEduardo Valentin { 373eb982001SEduardo Valentin int temp, ret; 374eb982001SEduardo Valentin 375eb982001SEduardo Valentin /* 376eb982001SEduardo Valentin * Need to add in the mcelsius domain, so we have a temperature 377eb982001SEduardo Valentin * the conv_table range 378eb982001SEduardo Valentin */ 379eb982001SEduardo Valentin ret = ti_bandgap_adc_to_mcelsius(bgp, adc_val, &temp); 380eb982001SEduardo Valentin if (ret < 0) 381eb982001SEduardo Valentin goto exit; 382eb982001SEduardo Valentin 383eb982001SEduardo Valentin temp += hyst_val; 384eb982001SEduardo Valentin 385eb982001SEduardo Valentin ret = ti_bandgap_mcelsius_to_adc(bgp, temp, sum); 386eb982001SEduardo Valentin 387eb982001SEduardo Valentin exit: 388eb982001SEduardo Valentin return ret; 389eb982001SEduardo Valentin } 390eb982001SEduardo Valentin 391eb982001SEduardo Valentin /*** Helper functions handling device Alert/Shutdown signals ***/ 392eb982001SEduardo Valentin 393eb982001SEduardo Valentin /** 394eb982001SEduardo Valentin * ti_bandgap_unmask_interrupts() - unmasks the events of thot & tcold 395eb982001SEduardo Valentin * @bgp: struct ti_bandgap pointer 396eb982001SEduardo Valentin * @id: bandgap sensor id 397eb982001SEduardo Valentin * @t_hot: hot temperature value to trigger alert signal 398eb982001SEduardo Valentin * @t_cold: cold temperature value to trigger alert signal 399eb982001SEduardo Valentin * 400eb982001SEduardo Valentin * Checks the requested t_hot and t_cold values and configures the IRQ event 401eb982001SEduardo Valentin * masks accordingly. Call this function only if bandgap features HAS(TALERT). 402eb982001SEduardo Valentin */ 403eb982001SEduardo Valentin static void ti_bandgap_unmask_interrupts(struct ti_bandgap *bgp, int id, 404eb982001SEduardo Valentin u32 t_hot, u32 t_cold) 405eb982001SEduardo Valentin { 406eb982001SEduardo Valentin struct temp_sensor_registers *tsr; 407eb982001SEduardo Valentin u32 temp, reg_val; 408eb982001SEduardo Valentin 409eb982001SEduardo Valentin /* Read the current on die temperature */ 410eb982001SEduardo Valentin temp = ti_bandgap_read_temp(bgp, id); 411eb982001SEduardo Valentin 412eb982001SEduardo Valentin tsr = bgp->conf->sensors[id].registers; 413eb982001SEduardo Valentin reg_val = ti_bandgap_readl(bgp, tsr->bgap_mask_ctrl); 414eb982001SEduardo Valentin 415eb982001SEduardo Valentin if (temp < t_hot) 416eb982001SEduardo Valentin reg_val |= tsr->mask_hot_mask; 417eb982001SEduardo Valentin else 418eb982001SEduardo Valentin reg_val &= ~tsr->mask_hot_mask; 419eb982001SEduardo Valentin 420eb982001SEduardo Valentin if (t_cold < temp) 421eb982001SEduardo Valentin reg_val |= tsr->mask_cold_mask; 422eb982001SEduardo Valentin else 423eb982001SEduardo Valentin reg_val &= ~tsr->mask_cold_mask; 424eb982001SEduardo Valentin ti_bandgap_writel(bgp, reg_val, tsr->bgap_mask_ctrl); 425eb982001SEduardo Valentin } 426eb982001SEduardo Valentin 427eb982001SEduardo Valentin /** 428eb982001SEduardo Valentin * ti_bandgap_update_alert_threshold() - sequence to update thresholds 429eb982001SEduardo Valentin * @bgp: struct ti_bandgap pointer 430eb982001SEduardo Valentin * @id: bandgap sensor id 431eb982001SEduardo Valentin * @val: value (ADC) of a new threshold 432eb982001SEduardo Valentin * @hot: desired threshold to be updated. true if threshold hot, false if 433eb982001SEduardo Valentin * threshold cold 434eb982001SEduardo Valentin * 435eb982001SEduardo Valentin * It will program the required thresholds (hot and cold) for TALERT signal. 436eb982001SEduardo Valentin * This function can be used to update t_hot or t_cold, depending on @hot value. 437eb982001SEduardo Valentin * It checks the resulting t_hot and t_cold values, based on the new passed @val 438eb982001SEduardo Valentin * and configures the thresholds so that t_hot is always greater than t_cold. 439eb982001SEduardo Valentin * Call this function only if bandgap features HAS(TALERT). 440eb982001SEduardo Valentin * 441eb982001SEduardo Valentin * Return: 0 if no error, else corresponding error 442eb982001SEduardo Valentin */ 443eb982001SEduardo Valentin static int ti_bandgap_update_alert_threshold(struct ti_bandgap *bgp, int id, 444eb982001SEduardo Valentin int val, bool hot) 445eb982001SEduardo Valentin { 446eb982001SEduardo Valentin struct temp_sensor_data *ts_data = bgp->conf->sensors[id].ts_data; 447eb982001SEduardo Valentin struct temp_sensor_registers *tsr; 448e9a90d04SKeerthy u32 thresh_val, reg_val, t_hot, t_cold, ctrl; 449eb982001SEduardo Valentin int err = 0; 450eb982001SEduardo Valentin 451eb982001SEduardo Valentin tsr = bgp->conf->sensors[id].registers; 452eb982001SEduardo Valentin 453eb982001SEduardo Valentin /* obtain the current value */ 454eb982001SEduardo Valentin thresh_val = ti_bandgap_readl(bgp, tsr->bgap_threshold); 455eb982001SEduardo Valentin t_cold = (thresh_val & tsr->threshold_tcold_mask) >> 456eb982001SEduardo Valentin __ffs(tsr->threshold_tcold_mask); 457eb982001SEduardo Valentin t_hot = (thresh_val & tsr->threshold_thot_mask) >> 458eb982001SEduardo Valentin __ffs(tsr->threshold_thot_mask); 459eb982001SEduardo Valentin if (hot) 460eb982001SEduardo Valentin t_hot = val; 461eb982001SEduardo Valentin else 462eb982001SEduardo Valentin t_cold = val; 463eb982001SEduardo Valentin 464eb982001SEduardo Valentin if (t_cold > t_hot) { 465eb982001SEduardo Valentin if (hot) 466eb982001SEduardo Valentin err = ti_bandgap_add_hyst(bgp, t_hot, 467eb982001SEduardo Valentin -ts_data->hyst_val, 468eb982001SEduardo Valentin &t_cold); 469eb982001SEduardo Valentin else 470eb982001SEduardo Valentin err = ti_bandgap_add_hyst(bgp, t_cold, 471eb982001SEduardo Valentin ts_data->hyst_val, 472eb982001SEduardo Valentin &t_hot); 473eb982001SEduardo Valentin } 474eb982001SEduardo Valentin 475eb982001SEduardo Valentin /* write the new threshold values */ 476eb982001SEduardo Valentin reg_val = thresh_val & 477eb982001SEduardo Valentin ~(tsr->threshold_thot_mask | tsr->threshold_tcold_mask); 478eb982001SEduardo Valentin reg_val |= (t_hot << __ffs(tsr->threshold_thot_mask)) | 479eb982001SEduardo Valentin (t_cold << __ffs(tsr->threshold_tcold_mask)); 480e9a90d04SKeerthy 481e9a90d04SKeerthy /** 482e9a90d04SKeerthy * Errata i813: 483e9a90d04SKeerthy * Spurious Thermal Alert: Talert can happen randomly while the device 484e9a90d04SKeerthy * remains under the temperature limit defined for this event to trig. 485e9a90d04SKeerthy * This spurious event is caused by a incorrect re-synchronization 486e9a90d04SKeerthy * between clock domains. The comparison between configured threshold 487e9a90d04SKeerthy * and current temperature value can happen while the value is 488e9a90d04SKeerthy * transitioning (metastable), thus causing inappropriate event 489e9a90d04SKeerthy * generation. No spurious event occurs as long as the threshold value 490e9a90d04SKeerthy * stays unchanged. Spurious event can be generated while a thermal 491e9a90d04SKeerthy * alert threshold is modified in 492e9a90d04SKeerthy * CONTROL_BANDGAP_THRESHOLD_MPU/GPU/CORE/DSPEVE/IVA_n. 493e9a90d04SKeerthy */ 494e9a90d04SKeerthy 495e9a90d04SKeerthy if (TI_BANDGAP_HAS(bgp, ERRATA_813)) { 496e9a90d04SKeerthy /* Mask t_hot and t_cold events at the IP Level */ 497e9a90d04SKeerthy ctrl = ti_bandgap_readl(bgp, tsr->bgap_mask_ctrl); 498e9a90d04SKeerthy 499e9a90d04SKeerthy if (hot) 500e9a90d04SKeerthy ctrl &= ~tsr->mask_hot_mask; 501e9a90d04SKeerthy else 502e9a90d04SKeerthy ctrl &= ~tsr->mask_cold_mask; 503e9a90d04SKeerthy 504e9a90d04SKeerthy ti_bandgap_writel(bgp, ctrl, tsr->bgap_mask_ctrl); 505e9a90d04SKeerthy } 506e9a90d04SKeerthy 507e9a90d04SKeerthy /* Write the threshold value */ 508eb982001SEduardo Valentin ti_bandgap_writel(bgp, reg_val, tsr->bgap_threshold); 509eb982001SEduardo Valentin 510e9a90d04SKeerthy if (TI_BANDGAP_HAS(bgp, ERRATA_813)) { 511e9a90d04SKeerthy /* Unmask t_hot and t_cold events at the IP Level */ 512e9a90d04SKeerthy ctrl = ti_bandgap_readl(bgp, tsr->bgap_mask_ctrl); 513e9a90d04SKeerthy if (hot) 514e9a90d04SKeerthy ctrl |= tsr->mask_hot_mask; 515e9a90d04SKeerthy else 516e9a90d04SKeerthy ctrl |= tsr->mask_cold_mask; 517e9a90d04SKeerthy 518e9a90d04SKeerthy ti_bandgap_writel(bgp, ctrl, tsr->bgap_mask_ctrl); 519e9a90d04SKeerthy } 520e9a90d04SKeerthy 521eb982001SEduardo Valentin if (err) { 522eb982001SEduardo Valentin dev_err(bgp->dev, "failed to reprogram thot threshold\n"); 523eb982001SEduardo Valentin err = -EIO; 524eb982001SEduardo Valentin goto exit; 525eb982001SEduardo Valentin } 526eb982001SEduardo Valentin 527eb982001SEduardo Valentin ti_bandgap_unmask_interrupts(bgp, id, t_hot, t_cold); 528eb982001SEduardo Valentin exit: 529eb982001SEduardo Valentin return err; 530eb982001SEduardo Valentin } 531eb982001SEduardo Valentin 532eb982001SEduardo Valentin /** 533eb982001SEduardo Valentin * ti_bandgap_validate() - helper to check the sanity of a struct ti_bandgap 534eb982001SEduardo Valentin * @bgp: struct ti_bandgap pointer 535eb982001SEduardo Valentin * @id: bandgap sensor id 536eb982001SEduardo Valentin * 537eb982001SEduardo Valentin * Checks if the bandgap pointer is valid and if the sensor id is also 538eb982001SEduardo Valentin * applicable. 539eb982001SEduardo Valentin * 540eb982001SEduardo Valentin * Return: 0 if no errors, -EINVAL for invalid @bgp pointer or -ERANGE if 541eb982001SEduardo Valentin * @id cannot index @bgp sensors. 542eb982001SEduardo Valentin */ 543eb982001SEduardo Valentin static inline int ti_bandgap_validate(struct ti_bandgap *bgp, int id) 544eb982001SEduardo Valentin { 545eb982001SEduardo Valentin int ret = 0; 546eb982001SEduardo Valentin 5470c12b5acSEduardo Valentin if (!bgp || IS_ERR(bgp)) { 548eb982001SEduardo Valentin pr_err("%s: invalid bandgap pointer\n", __func__); 549eb982001SEduardo Valentin ret = -EINVAL; 550eb982001SEduardo Valentin goto exit; 551eb982001SEduardo Valentin } 552eb982001SEduardo Valentin 553eb982001SEduardo Valentin if ((id < 0) || (id >= bgp->conf->sensor_count)) { 554eb982001SEduardo Valentin dev_err(bgp->dev, "%s: sensor id out of range (%d)\n", 555eb982001SEduardo Valentin __func__, id); 556eb982001SEduardo Valentin ret = -ERANGE; 557eb982001SEduardo Valentin } 558eb982001SEduardo Valentin 559eb982001SEduardo Valentin exit: 560eb982001SEduardo Valentin return ret; 561eb982001SEduardo Valentin } 562eb982001SEduardo Valentin 563eb982001SEduardo Valentin /** 564eb982001SEduardo Valentin * _ti_bandgap_write_threshold() - helper to update TALERT t_cold or t_hot 565eb982001SEduardo Valentin * @bgp: struct ti_bandgap pointer 566eb982001SEduardo Valentin * @id: bandgap sensor id 567eb982001SEduardo Valentin * @val: value (mCelsius) of a new threshold 568eb982001SEduardo Valentin * @hot: desired threshold to be updated. true if threshold hot, false if 569eb982001SEduardo Valentin * threshold cold 570eb982001SEduardo Valentin * 571eb982001SEduardo Valentin * It will update the required thresholds (hot and cold) for TALERT signal. 572eb982001SEduardo Valentin * This function can be used to update t_hot or t_cold, depending on @hot value. 573eb982001SEduardo Valentin * Validates the mCelsius range and update the requested threshold. 574eb982001SEduardo Valentin * Call this function only if bandgap features HAS(TALERT). 575eb982001SEduardo Valentin * 576eb982001SEduardo Valentin * Return: 0 if no error, else corresponding error value. 577eb982001SEduardo Valentin */ 578eb982001SEduardo Valentin static int _ti_bandgap_write_threshold(struct ti_bandgap *bgp, int id, int val, 579eb982001SEduardo Valentin bool hot) 580eb982001SEduardo Valentin { 581eb982001SEduardo Valentin struct temp_sensor_data *ts_data; 582eb982001SEduardo Valentin struct temp_sensor_registers *tsr; 583eb982001SEduardo Valentin u32 adc_val; 584eb982001SEduardo Valentin int ret; 585eb982001SEduardo Valentin 586eb982001SEduardo Valentin ret = ti_bandgap_validate(bgp, id); 587eb982001SEduardo Valentin if (ret) 588eb982001SEduardo Valentin goto exit; 589eb982001SEduardo Valentin 590eb982001SEduardo Valentin if (!TI_BANDGAP_HAS(bgp, TALERT)) { 591eb982001SEduardo Valentin ret = -ENOTSUPP; 592eb982001SEduardo Valentin goto exit; 593eb982001SEduardo Valentin } 594eb982001SEduardo Valentin 595eb982001SEduardo Valentin ts_data = bgp->conf->sensors[id].ts_data; 596eb982001SEduardo Valentin tsr = bgp->conf->sensors[id].registers; 597eb982001SEduardo Valentin if (hot) { 598eb982001SEduardo Valentin if (val < ts_data->min_temp + ts_data->hyst_val) 599eb982001SEduardo Valentin ret = -EINVAL; 600eb982001SEduardo Valentin } else { 601eb982001SEduardo Valentin if (val > ts_data->max_temp + ts_data->hyst_val) 602eb982001SEduardo Valentin ret = -EINVAL; 603eb982001SEduardo Valentin } 604eb982001SEduardo Valentin 605eb982001SEduardo Valentin if (ret) 606eb982001SEduardo Valentin goto exit; 607eb982001SEduardo Valentin 608eb982001SEduardo Valentin ret = ti_bandgap_mcelsius_to_adc(bgp, val, &adc_val); 609eb982001SEduardo Valentin if (ret < 0) 610eb982001SEduardo Valentin goto exit; 611eb982001SEduardo Valentin 612eb982001SEduardo Valentin spin_lock(&bgp->lock); 613eb982001SEduardo Valentin ret = ti_bandgap_update_alert_threshold(bgp, id, adc_val, hot); 614eb982001SEduardo Valentin spin_unlock(&bgp->lock); 615eb982001SEduardo Valentin 616eb982001SEduardo Valentin exit: 617eb982001SEduardo Valentin return ret; 618eb982001SEduardo Valentin } 619eb982001SEduardo Valentin 620eb982001SEduardo Valentin /** 621eb982001SEduardo Valentin * _ti_bandgap_read_threshold() - helper to read TALERT t_cold or t_hot 622eb982001SEduardo Valentin * @bgp: struct ti_bandgap pointer 623eb982001SEduardo Valentin * @id: bandgap sensor id 624eb982001SEduardo Valentin * @val: value (mCelsius) of a threshold 625eb982001SEduardo Valentin * @hot: desired threshold to be read. true if threshold hot, false if 626eb982001SEduardo Valentin * threshold cold 627eb982001SEduardo Valentin * 628eb982001SEduardo Valentin * It will fetch the required thresholds (hot and cold) for TALERT signal. 629eb982001SEduardo Valentin * This function can be used to read t_hot or t_cold, depending on @hot value. 630eb982001SEduardo Valentin * Call this function only if bandgap features HAS(TALERT). 631eb982001SEduardo Valentin * 632eb982001SEduardo Valentin * Return: 0 if no error, -ENOTSUPP if it has no TALERT support, or the 633eb982001SEduardo Valentin * corresponding error value if some operation fails. 634eb982001SEduardo Valentin */ 635eb982001SEduardo Valentin static int _ti_bandgap_read_threshold(struct ti_bandgap *bgp, int id, 636eb982001SEduardo Valentin int *val, bool hot) 637eb982001SEduardo Valentin { 638eb982001SEduardo Valentin struct temp_sensor_registers *tsr; 639eb982001SEduardo Valentin u32 temp, mask; 640eb982001SEduardo Valentin int ret = 0; 641eb982001SEduardo Valentin 642eb982001SEduardo Valentin ret = ti_bandgap_validate(bgp, id); 643eb982001SEduardo Valentin if (ret) 644eb982001SEduardo Valentin goto exit; 645eb982001SEduardo Valentin 646eb982001SEduardo Valentin if (!TI_BANDGAP_HAS(bgp, TALERT)) { 647eb982001SEduardo Valentin ret = -ENOTSUPP; 648eb982001SEduardo Valentin goto exit; 649eb982001SEduardo Valentin } 650eb982001SEduardo Valentin 651eb982001SEduardo Valentin tsr = bgp->conf->sensors[id].registers; 652eb982001SEduardo Valentin if (hot) 653eb982001SEduardo Valentin mask = tsr->threshold_thot_mask; 654eb982001SEduardo Valentin else 655eb982001SEduardo Valentin mask = tsr->threshold_tcold_mask; 656eb982001SEduardo Valentin 657eb982001SEduardo Valentin temp = ti_bandgap_readl(bgp, tsr->bgap_threshold); 658eb982001SEduardo Valentin temp = (temp & mask) >> __ffs(mask); 659eb982001SEduardo Valentin ret |= ti_bandgap_adc_to_mcelsius(bgp, temp, &temp); 660eb982001SEduardo Valentin if (ret) { 661eb982001SEduardo Valentin dev_err(bgp->dev, "failed to read thot\n"); 662eb982001SEduardo Valentin ret = -EIO; 663eb982001SEduardo Valentin goto exit; 664eb982001SEduardo Valentin } 665eb982001SEduardo Valentin 666eb982001SEduardo Valentin *val = temp; 667eb982001SEduardo Valentin 668eb982001SEduardo Valentin exit: 669eb982001SEduardo Valentin return ret; 670eb982001SEduardo Valentin } 671eb982001SEduardo Valentin 672eb982001SEduardo Valentin /*** Exposed APIs ***/ 673eb982001SEduardo Valentin 674eb982001SEduardo Valentin /** 675eb982001SEduardo Valentin * ti_bandgap_read_thot() - reads sensor current thot 676eb982001SEduardo Valentin * @bgp: pointer to bandgap instance 677eb982001SEduardo Valentin * @id: sensor id 678eb982001SEduardo Valentin * @thot: resulting current thot value 679eb982001SEduardo Valentin * 680eb982001SEduardo Valentin * Return: 0 on success or the proper error code 681eb982001SEduardo Valentin */ 682eb982001SEduardo Valentin int ti_bandgap_read_thot(struct ti_bandgap *bgp, int id, int *thot) 683eb982001SEduardo Valentin { 684eb982001SEduardo Valentin return _ti_bandgap_read_threshold(bgp, id, thot, true); 685eb982001SEduardo Valentin } 686eb982001SEduardo Valentin 687eb982001SEduardo Valentin /** 688eb982001SEduardo Valentin * ti_bandgap_write_thot() - sets sensor current thot 689eb982001SEduardo Valentin * @bgp: pointer to bandgap instance 690eb982001SEduardo Valentin * @id: sensor id 691eb982001SEduardo Valentin * @val: desired thot value 692eb982001SEduardo Valentin * 693eb982001SEduardo Valentin * Return: 0 on success or the proper error code 694eb982001SEduardo Valentin */ 695eb982001SEduardo Valentin int ti_bandgap_write_thot(struct ti_bandgap *bgp, int id, int val) 696eb982001SEduardo Valentin { 697eb982001SEduardo Valentin return _ti_bandgap_write_threshold(bgp, id, val, true); 698eb982001SEduardo Valentin } 699eb982001SEduardo Valentin 700eb982001SEduardo Valentin /** 701eb982001SEduardo Valentin * ti_bandgap_read_tcold() - reads sensor current tcold 702eb982001SEduardo Valentin * @bgp: pointer to bandgap instance 703eb982001SEduardo Valentin * @id: sensor id 704eb982001SEduardo Valentin * @tcold: resulting current tcold value 705eb982001SEduardo Valentin * 706eb982001SEduardo Valentin * Return: 0 on success or the proper error code 707eb982001SEduardo Valentin */ 708eb982001SEduardo Valentin int ti_bandgap_read_tcold(struct ti_bandgap *bgp, int id, int *tcold) 709eb982001SEduardo Valentin { 710eb982001SEduardo Valentin return _ti_bandgap_read_threshold(bgp, id, tcold, false); 711eb982001SEduardo Valentin } 712eb982001SEduardo Valentin 713eb982001SEduardo Valentin /** 714eb982001SEduardo Valentin * ti_bandgap_write_tcold() - sets the sensor tcold 715eb982001SEduardo Valentin * @bgp: pointer to bandgap instance 716eb982001SEduardo Valentin * @id: sensor id 717eb982001SEduardo Valentin * @val: desired tcold value 718eb982001SEduardo Valentin * 719eb982001SEduardo Valentin * Return: 0 on success or the proper error code 720eb982001SEduardo Valentin */ 721eb982001SEduardo Valentin int ti_bandgap_write_tcold(struct ti_bandgap *bgp, int id, int val) 722eb982001SEduardo Valentin { 723eb982001SEduardo Valentin return _ti_bandgap_write_threshold(bgp, id, val, false); 724eb982001SEduardo Valentin } 725eb982001SEduardo Valentin 726eb982001SEduardo Valentin /** 727eb982001SEduardo Valentin * ti_bandgap_read_counter() - read the sensor counter 728eb982001SEduardo Valentin * @bgp: pointer to bandgap instance 729eb982001SEduardo Valentin * @id: sensor id 730eb982001SEduardo Valentin * @interval: resulting update interval in miliseconds 731eb982001SEduardo Valentin */ 732eb982001SEduardo Valentin static void ti_bandgap_read_counter(struct ti_bandgap *bgp, int id, 733eb982001SEduardo Valentin int *interval) 734eb982001SEduardo Valentin { 735eb982001SEduardo Valentin struct temp_sensor_registers *tsr; 736eb982001SEduardo Valentin int time; 737eb982001SEduardo Valentin 738eb982001SEduardo Valentin tsr = bgp->conf->sensors[id].registers; 739eb982001SEduardo Valentin time = ti_bandgap_readl(bgp, tsr->bgap_counter); 740eb982001SEduardo Valentin time = (time & tsr->counter_mask) >> 741eb982001SEduardo Valentin __ffs(tsr->counter_mask); 742eb982001SEduardo Valentin time = time * 1000 / bgp->clk_rate; 743eb982001SEduardo Valentin *interval = time; 744eb982001SEduardo Valentin } 745eb982001SEduardo Valentin 746eb982001SEduardo Valentin /** 747eb982001SEduardo Valentin * ti_bandgap_read_counter_delay() - read the sensor counter delay 748eb982001SEduardo Valentin * @bgp: pointer to bandgap instance 749eb982001SEduardo Valentin * @id: sensor id 750eb982001SEduardo Valentin * @interval: resulting update interval in miliseconds 751eb982001SEduardo Valentin */ 752eb982001SEduardo Valentin static void ti_bandgap_read_counter_delay(struct ti_bandgap *bgp, int id, 753eb982001SEduardo Valentin int *interval) 754eb982001SEduardo Valentin { 755eb982001SEduardo Valentin struct temp_sensor_registers *tsr; 756eb982001SEduardo Valentin int reg_val; 757eb982001SEduardo Valentin 758eb982001SEduardo Valentin tsr = bgp->conf->sensors[id].registers; 759eb982001SEduardo Valentin 760eb982001SEduardo Valentin reg_val = ti_bandgap_readl(bgp, tsr->bgap_mask_ctrl); 761eb982001SEduardo Valentin reg_val = (reg_val & tsr->mask_counter_delay_mask) >> 762eb982001SEduardo Valentin __ffs(tsr->mask_counter_delay_mask); 763eb982001SEduardo Valentin switch (reg_val) { 764eb982001SEduardo Valentin case 0: 765eb982001SEduardo Valentin *interval = 0; 766eb982001SEduardo Valentin break; 767eb982001SEduardo Valentin case 1: 768eb982001SEduardo Valentin *interval = 1; 769eb982001SEduardo Valentin break; 770eb982001SEduardo Valentin case 2: 771eb982001SEduardo Valentin *interval = 10; 772eb982001SEduardo Valentin break; 773eb982001SEduardo Valentin case 3: 774eb982001SEduardo Valentin *interval = 100; 775eb982001SEduardo Valentin break; 776eb982001SEduardo Valentin case 4: 777eb982001SEduardo Valentin *interval = 250; 778eb982001SEduardo Valentin break; 779eb982001SEduardo Valentin case 5: 780eb982001SEduardo Valentin *interval = 500; 781eb982001SEduardo Valentin break; 782eb982001SEduardo Valentin default: 783eb982001SEduardo Valentin dev_warn(bgp->dev, "Wrong counter delay value read from register %X", 784eb982001SEduardo Valentin reg_val); 785eb982001SEduardo Valentin } 786eb982001SEduardo Valentin } 787eb982001SEduardo Valentin 788eb982001SEduardo Valentin /** 789eb982001SEduardo Valentin * ti_bandgap_read_update_interval() - read the sensor update interval 790eb982001SEduardo Valentin * @bgp: pointer to bandgap instance 791eb982001SEduardo Valentin * @id: sensor id 792eb982001SEduardo Valentin * @interval: resulting update interval in miliseconds 793eb982001SEduardo Valentin * 794eb982001SEduardo Valentin * Return: 0 on success or the proper error code 795eb982001SEduardo Valentin */ 796eb982001SEduardo Valentin int ti_bandgap_read_update_interval(struct ti_bandgap *bgp, int id, 797eb982001SEduardo Valentin int *interval) 798eb982001SEduardo Valentin { 799eb982001SEduardo Valentin int ret = 0; 800eb982001SEduardo Valentin 801eb982001SEduardo Valentin ret = ti_bandgap_validate(bgp, id); 802eb982001SEduardo Valentin if (ret) 803eb982001SEduardo Valentin goto exit; 804eb982001SEduardo Valentin 805eb982001SEduardo Valentin if (!TI_BANDGAP_HAS(bgp, COUNTER) && 806eb982001SEduardo Valentin !TI_BANDGAP_HAS(bgp, COUNTER_DELAY)) { 807eb982001SEduardo Valentin ret = -ENOTSUPP; 808eb982001SEduardo Valentin goto exit; 809eb982001SEduardo Valentin } 810eb982001SEduardo Valentin 811eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, COUNTER)) { 812eb982001SEduardo Valentin ti_bandgap_read_counter(bgp, id, interval); 813eb982001SEduardo Valentin goto exit; 814eb982001SEduardo Valentin } 815eb982001SEduardo Valentin 816eb982001SEduardo Valentin ti_bandgap_read_counter_delay(bgp, id, interval); 817eb982001SEduardo Valentin exit: 818eb982001SEduardo Valentin return ret; 819eb982001SEduardo Valentin } 820eb982001SEduardo Valentin 821eb982001SEduardo Valentin /** 822eb982001SEduardo Valentin * ti_bandgap_write_counter_delay() - set the counter_delay 823eb982001SEduardo Valentin * @bgp: pointer to bandgap instance 824eb982001SEduardo Valentin * @id: sensor id 825eb982001SEduardo Valentin * @interval: desired update interval in miliseconds 826eb982001SEduardo Valentin * 827eb982001SEduardo Valentin * Return: 0 on success or the proper error code 828eb982001SEduardo Valentin */ 829eb982001SEduardo Valentin static int ti_bandgap_write_counter_delay(struct ti_bandgap *bgp, int id, 830eb982001SEduardo Valentin u32 interval) 831eb982001SEduardo Valentin { 832eb982001SEduardo Valentin int rval; 833eb982001SEduardo Valentin 834eb982001SEduardo Valentin switch (interval) { 835eb982001SEduardo Valentin case 0: /* Immediate conversion */ 836eb982001SEduardo Valentin rval = 0x0; 837eb982001SEduardo Valentin break; 838eb982001SEduardo Valentin case 1: /* Conversion after ever 1ms */ 839eb982001SEduardo Valentin rval = 0x1; 840eb982001SEduardo Valentin break; 841eb982001SEduardo Valentin case 10: /* Conversion after ever 10ms */ 842eb982001SEduardo Valentin rval = 0x2; 843eb982001SEduardo Valentin break; 844eb982001SEduardo Valentin case 100: /* Conversion after ever 100ms */ 845eb982001SEduardo Valentin rval = 0x3; 846eb982001SEduardo Valentin break; 847eb982001SEduardo Valentin case 250: /* Conversion after ever 250ms */ 848eb982001SEduardo Valentin rval = 0x4; 849eb982001SEduardo Valentin break; 850eb982001SEduardo Valentin case 500: /* Conversion after ever 500ms */ 851eb982001SEduardo Valentin rval = 0x5; 852eb982001SEduardo Valentin break; 853eb982001SEduardo Valentin default: 854eb982001SEduardo Valentin dev_warn(bgp->dev, "Delay %d ms is not supported\n", interval); 855eb982001SEduardo Valentin return -EINVAL; 856eb982001SEduardo Valentin } 857eb982001SEduardo Valentin 858eb982001SEduardo Valentin spin_lock(&bgp->lock); 859eb982001SEduardo Valentin RMW_BITS(bgp, id, bgap_mask_ctrl, mask_counter_delay_mask, rval); 860eb982001SEduardo Valentin spin_unlock(&bgp->lock); 861eb982001SEduardo Valentin 862eb982001SEduardo Valentin return 0; 863eb982001SEduardo Valentin } 864eb982001SEduardo Valentin 865eb982001SEduardo Valentin /** 866eb982001SEduardo Valentin * ti_bandgap_write_counter() - set the bandgap sensor counter 867eb982001SEduardo Valentin * @bgp: pointer to bandgap instance 868eb982001SEduardo Valentin * @id: sensor id 869eb982001SEduardo Valentin * @interval: desired update interval in miliseconds 870eb982001SEduardo Valentin */ 871eb982001SEduardo Valentin static void ti_bandgap_write_counter(struct ti_bandgap *bgp, int id, 872eb982001SEduardo Valentin u32 interval) 873eb982001SEduardo Valentin { 874eb982001SEduardo Valentin interval = interval * bgp->clk_rate / 1000; 875eb982001SEduardo Valentin spin_lock(&bgp->lock); 876eb982001SEduardo Valentin RMW_BITS(bgp, id, bgap_counter, counter_mask, interval); 877eb982001SEduardo Valentin spin_unlock(&bgp->lock); 878eb982001SEduardo Valentin } 879eb982001SEduardo Valentin 880eb982001SEduardo Valentin /** 881eb982001SEduardo Valentin * ti_bandgap_write_update_interval() - set the update interval 882eb982001SEduardo Valentin * @bgp: pointer to bandgap instance 883eb982001SEduardo Valentin * @id: sensor id 884eb982001SEduardo Valentin * @interval: desired update interval in miliseconds 885eb982001SEduardo Valentin * 886eb982001SEduardo Valentin * Return: 0 on success or the proper error code 887eb982001SEduardo Valentin */ 888eb982001SEduardo Valentin int ti_bandgap_write_update_interval(struct ti_bandgap *bgp, 889eb982001SEduardo Valentin int id, u32 interval) 890eb982001SEduardo Valentin { 891eb982001SEduardo Valentin int ret = ti_bandgap_validate(bgp, id); 892eb982001SEduardo Valentin if (ret) 893eb982001SEduardo Valentin goto exit; 894eb982001SEduardo Valentin 895eb982001SEduardo Valentin if (!TI_BANDGAP_HAS(bgp, COUNTER) && 896eb982001SEduardo Valentin !TI_BANDGAP_HAS(bgp, COUNTER_DELAY)) { 897eb982001SEduardo Valentin ret = -ENOTSUPP; 898eb982001SEduardo Valentin goto exit; 899eb982001SEduardo Valentin } 900eb982001SEduardo Valentin 901eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, COUNTER)) { 902eb982001SEduardo Valentin ti_bandgap_write_counter(bgp, id, interval); 903eb982001SEduardo Valentin goto exit; 904eb982001SEduardo Valentin } 905eb982001SEduardo Valentin 906eb982001SEduardo Valentin ret = ti_bandgap_write_counter_delay(bgp, id, interval); 907eb982001SEduardo Valentin exit: 908eb982001SEduardo Valentin return ret; 909eb982001SEduardo Valentin } 910eb982001SEduardo Valentin 911eb982001SEduardo Valentin /** 912eb982001SEduardo Valentin * ti_bandgap_read_temperature() - report current temperature 913eb982001SEduardo Valentin * @bgp: pointer to bandgap instance 914eb982001SEduardo Valentin * @id: sensor id 915eb982001SEduardo Valentin * @temperature: resulting temperature 916eb982001SEduardo Valentin * 917eb982001SEduardo Valentin * Return: 0 on success or the proper error code 918eb982001SEduardo Valentin */ 919eb982001SEduardo Valentin int ti_bandgap_read_temperature(struct ti_bandgap *bgp, int id, 920eb982001SEduardo Valentin int *temperature) 921eb982001SEduardo Valentin { 922eb982001SEduardo Valentin u32 temp; 923eb982001SEduardo Valentin int ret; 924eb982001SEduardo Valentin 925eb982001SEduardo Valentin ret = ti_bandgap_validate(bgp, id); 926eb982001SEduardo Valentin if (ret) 927eb982001SEduardo Valentin return ret; 928eb982001SEduardo Valentin 929eb982001SEduardo Valentin spin_lock(&bgp->lock); 930eb982001SEduardo Valentin temp = ti_bandgap_read_temp(bgp, id); 931eb982001SEduardo Valentin spin_unlock(&bgp->lock); 932eb982001SEduardo Valentin 933eb982001SEduardo Valentin ret |= ti_bandgap_adc_to_mcelsius(bgp, temp, &temp); 934eb982001SEduardo Valentin if (ret) 935eb982001SEduardo Valentin return -EIO; 936eb982001SEduardo Valentin 937eb982001SEduardo Valentin *temperature = temp; 938eb982001SEduardo Valentin 939eb982001SEduardo Valentin return 0; 940eb982001SEduardo Valentin } 941eb982001SEduardo Valentin 942eb982001SEduardo Valentin /** 943eb982001SEduardo Valentin * ti_bandgap_set_sensor_data() - helper function to store thermal 944eb982001SEduardo Valentin * framework related data. 945eb982001SEduardo Valentin * @bgp: pointer to bandgap instance 946eb982001SEduardo Valentin * @id: sensor id 947eb982001SEduardo Valentin * @data: thermal framework related data to be stored 948eb982001SEduardo Valentin * 949eb982001SEduardo Valentin * Return: 0 on success or the proper error code 950eb982001SEduardo Valentin */ 951eb982001SEduardo Valentin int ti_bandgap_set_sensor_data(struct ti_bandgap *bgp, int id, void *data) 952eb982001SEduardo Valentin { 953eb982001SEduardo Valentin int ret = ti_bandgap_validate(bgp, id); 954eb982001SEduardo Valentin if (ret) 955eb982001SEduardo Valentin return ret; 956eb982001SEduardo Valentin 957eb982001SEduardo Valentin bgp->regval[id].data = data; 958eb982001SEduardo Valentin 959eb982001SEduardo Valentin return 0; 960eb982001SEduardo Valentin } 961eb982001SEduardo Valentin 962eb982001SEduardo Valentin /** 963eb982001SEduardo Valentin * ti_bandgap_get_sensor_data() - helper function to get thermal 964eb982001SEduardo Valentin * framework related data. 965eb982001SEduardo Valentin * @bgp: pointer to bandgap instance 966eb982001SEduardo Valentin * @id: sensor id 967eb982001SEduardo Valentin * 968eb982001SEduardo Valentin * Return: data stored by set function with sensor id on success or NULL 969eb982001SEduardo Valentin */ 970eb982001SEduardo Valentin void *ti_bandgap_get_sensor_data(struct ti_bandgap *bgp, int id) 971eb982001SEduardo Valentin { 972eb982001SEduardo Valentin int ret = ti_bandgap_validate(bgp, id); 973eb982001SEduardo Valentin if (ret) 974eb982001SEduardo Valentin return ERR_PTR(ret); 975eb982001SEduardo Valentin 976eb982001SEduardo Valentin return bgp->regval[id].data; 977eb982001SEduardo Valentin } 978eb982001SEduardo Valentin 979eb982001SEduardo Valentin /*** Helper functions used during device initialization ***/ 980eb982001SEduardo Valentin 981eb982001SEduardo Valentin /** 982eb982001SEduardo Valentin * ti_bandgap_force_single_read() - executes 1 single ADC conversion 983eb982001SEduardo Valentin * @bgp: pointer to struct ti_bandgap 984eb982001SEduardo Valentin * @id: sensor id which it is desired to read 1 temperature 985eb982001SEduardo Valentin * 986eb982001SEduardo Valentin * Used to initialize the conversion state machine and set it to a valid 987eb982001SEduardo Valentin * state. Called during device initialization and context restore events. 988eb982001SEduardo Valentin * 989eb982001SEduardo Valentin * Return: 0 990eb982001SEduardo Valentin */ 991eb982001SEduardo Valentin static int 992eb982001SEduardo Valentin ti_bandgap_force_single_read(struct ti_bandgap *bgp, int id) 993eb982001SEduardo Valentin { 994eb982001SEduardo Valentin u32 temp = 0, counter = 1000; 995eb982001SEduardo Valentin 996eb982001SEduardo Valentin /* Select single conversion mode */ 997eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, MODE_CONFIG)) 998eb982001SEduardo Valentin RMW_BITS(bgp, id, bgap_mode_ctrl, mode_ctrl_mask, 0); 999eb982001SEduardo Valentin 1000eb982001SEduardo Valentin /* Start of Conversion = 1 */ 1001eb982001SEduardo Valentin RMW_BITS(bgp, id, temp_sensor_ctrl, bgap_soc_mask, 1); 1002eb982001SEduardo Valentin /* Wait until DTEMP is updated */ 1003eb982001SEduardo Valentin temp = ti_bandgap_read_temp(bgp, id); 1004eb982001SEduardo Valentin 1005eb982001SEduardo Valentin while ((temp == 0) && --counter) 1006eb982001SEduardo Valentin temp = ti_bandgap_read_temp(bgp, id); 1007eb982001SEduardo Valentin /* REVISIT: Check correct condition for end of conversion */ 1008eb982001SEduardo Valentin 1009eb982001SEduardo Valentin /* Start of Conversion = 0 */ 1010eb982001SEduardo Valentin RMW_BITS(bgp, id, temp_sensor_ctrl, bgap_soc_mask, 0); 1011eb982001SEduardo Valentin 1012eb982001SEduardo Valentin return 0; 1013eb982001SEduardo Valentin } 1014eb982001SEduardo Valentin 1015eb982001SEduardo Valentin /** 1016eb982001SEduardo Valentin * ti_bandgap_set_continous_mode() - One time enabling of continuous mode 1017eb982001SEduardo Valentin * @bgp: pointer to struct ti_bandgap 1018eb982001SEduardo Valentin * 1019eb982001SEduardo Valentin * Call this function only if HAS(MODE_CONFIG) is set. As this driver may 1020eb982001SEduardo Valentin * be used for junction temperature monitoring, it is desirable that the 1021eb982001SEduardo Valentin * sensors are operational all the time, so that alerts are generated 1022eb982001SEduardo Valentin * properly. 1023eb982001SEduardo Valentin * 1024eb982001SEduardo Valentin * Return: 0 1025eb982001SEduardo Valentin */ 1026eb982001SEduardo Valentin static int ti_bandgap_set_continuous_mode(struct ti_bandgap *bgp) 1027eb982001SEduardo Valentin { 1028eb982001SEduardo Valentin int i; 1029eb982001SEduardo Valentin 1030eb982001SEduardo Valentin for (i = 0; i < bgp->conf->sensor_count; i++) { 1031eb982001SEduardo Valentin /* Perform a single read just before enabling continuous */ 1032eb982001SEduardo Valentin ti_bandgap_force_single_read(bgp, i); 1033eb982001SEduardo Valentin RMW_BITS(bgp, i, bgap_mode_ctrl, mode_ctrl_mask, 1); 1034eb982001SEduardo Valentin } 1035eb982001SEduardo Valentin 1036eb982001SEduardo Valentin return 0; 1037eb982001SEduardo Valentin } 1038eb982001SEduardo Valentin 1039eb982001SEduardo Valentin /** 1040eb982001SEduardo Valentin * ti_bandgap_get_trend() - To fetch the temperature trend of a sensor 1041eb982001SEduardo Valentin * @bgp: pointer to struct ti_bandgap 1042eb982001SEduardo Valentin * @id: id of the individual sensor 1043eb982001SEduardo Valentin * @trend: Pointer to trend. 1044eb982001SEduardo Valentin * 1045eb982001SEduardo Valentin * This function needs to be called to fetch the temperature trend of a 1046eb982001SEduardo Valentin * Particular sensor. The function computes the difference in temperature 1047eb982001SEduardo Valentin * w.r.t time. For the bandgaps with built in history buffer the temperatures 1048eb982001SEduardo Valentin * are read from the buffer and for those without the Buffer -ENOTSUPP is 1049eb982001SEduardo Valentin * returned. 1050eb982001SEduardo Valentin * 1051eb982001SEduardo Valentin * Return: 0 if no error, else return corresponding error. If no 1052eb982001SEduardo Valentin * error then the trend value is passed on to trend parameter 1053eb982001SEduardo Valentin */ 1054eb982001SEduardo Valentin int ti_bandgap_get_trend(struct ti_bandgap *bgp, int id, int *trend) 1055eb982001SEduardo Valentin { 1056eb982001SEduardo Valentin struct temp_sensor_registers *tsr; 1057eb982001SEduardo Valentin u32 temp1, temp2, reg1, reg2; 1058eb982001SEduardo Valentin int t1, t2, interval, ret = 0; 1059eb982001SEduardo Valentin 1060eb982001SEduardo Valentin ret = ti_bandgap_validate(bgp, id); 1061eb982001SEduardo Valentin if (ret) 1062eb982001SEduardo Valentin goto exit; 1063eb982001SEduardo Valentin 1064eb982001SEduardo Valentin if (!TI_BANDGAP_HAS(bgp, HISTORY_BUFFER) || 1065eb982001SEduardo Valentin !TI_BANDGAP_HAS(bgp, FREEZE_BIT)) { 1066eb982001SEduardo Valentin ret = -ENOTSUPP; 1067eb982001SEduardo Valentin goto exit; 1068eb982001SEduardo Valentin } 1069eb982001SEduardo Valentin 1070ba0049eaSEduardo Valentin spin_lock(&bgp->lock); 1071ba0049eaSEduardo Valentin 1072eb982001SEduardo Valentin tsr = bgp->conf->sensors[id].registers; 1073eb982001SEduardo Valentin 1074eb982001SEduardo Valentin /* Freeze and read the last 2 valid readings */ 1075ba0049eaSEduardo Valentin RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 1); 1076eb982001SEduardo Valentin reg1 = tsr->ctrl_dtemp_1; 1077eb982001SEduardo Valentin reg2 = tsr->ctrl_dtemp_2; 1078eb982001SEduardo Valentin 1079eb982001SEduardo Valentin /* read temperature from history buffer */ 1080eb982001SEduardo Valentin temp1 = ti_bandgap_readl(bgp, reg1); 1081eb982001SEduardo Valentin temp1 &= tsr->bgap_dtemp_mask; 1082eb982001SEduardo Valentin 1083eb982001SEduardo Valentin temp2 = ti_bandgap_readl(bgp, reg2); 1084eb982001SEduardo Valentin temp2 &= tsr->bgap_dtemp_mask; 1085eb982001SEduardo Valentin 1086eb982001SEduardo Valentin /* Convert from adc values to mCelsius temperature */ 1087eb982001SEduardo Valentin ret = ti_bandgap_adc_to_mcelsius(bgp, temp1, &t1); 1088eb982001SEduardo Valentin if (ret) 1089ba0049eaSEduardo Valentin goto unfreeze; 1090eb982001SEduardo Valentin 1091eb982001SEduardo Valentin ret = ti_bandgap_adc_to_mcelsius(bgp, temp2, &t2); 1092eb982001SEduardo Valentin if (ret) 1093ba0049eaSEduardo Valentin goto unfreeze; 1094eb982001SEduardo Valentin 1095eb982001SEduardo Valentin /* Fetch the update interval */ 1096eb982001SEduardo Valentin ret = ti_bandgap_read_update_interval(bgp, id, &interval); 1097e838ff81SRanganath Krishnan if (ret) 1098ba0049eaSEduardo Valentin goto unfreeze; 1099eb982001SEduardo Valentin 1100e838ff81SRanganath Krishnan /* Set the interval to 1 ms if bandgap counter delay is not set */ 1101e838ff81SRanganath Krishnan if (interval == 0) 1102e838ff81SRanganath Krishnan interval = 1; 1103e838ff81SRanganath Krishnan 1104eb982001SEduardo Valentin *trend = (t1 - t2) / interval; 1105eb982001SEduardo Valentin 1106eb982001SEduardo Valentin dev_dbg(bgp->dev, "The temperatures are t1 = %d and t2 = %d and trend =%d\n", 1107eb982001SEduardo Valentin t1, t2, *trend); 1108eb982001SEduardo Valentin 1109ba0049eaSEduardo Valentin unfreeze: 1110ba0049eaSEduardo Valentin RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 0); 1111ba0049eaSEduardo Valentin spin_unlock(&bgp->lock); 1112eb982001SEduardo Valentin exit: 1113eb982001SEduardo Valentin return ret; 1114eb982001SEduardo Valentin } 1115eb982001SEduardo Valentin 1116eb982001SEduardo Valentin /** 1117eb982001SEduardo Valentin * ti_bandgap_tshut_init() - setup and initialize tshut handling 1118eb982001SEduardo Valentin * @bgp: pointer to struct ti_bandgap 1119eb982001SEduardo Valentin * @pdev: pointer to device struct platform_device 1120eb982001SEduardo Valentin * 1121eb982001SEduardo Valentin * Call this function only in case the bandgap features HAS(TSHUT). 1122eb982001SEduardo Valentin * In this case, the driver needs to handle the TSHUT signal as an IRQ. 1123eb982001SEduardo Valentin * The IRQ is wired as a GPIO, and for this purpose, it is required 1124eb982001SEduardo Valentin * to specify which GPIO line is used. TSHUT IRQ is fired anytime 1125eb982001SEduardo Valentin * one of the bandgap sensors violates the TSHUT high/hot threshold. 1126eb982001SEduardo Valentin * And in that case, the system must go off. 1127eb982001SEduardo Valentin * 1128eb982001SEduardo Valentin * Return: 0 if no error, else error status 1129eb982001SEduardo Valentin */ 1130eb982001SEduardo Valentin static int ti_bandgap_tshut_init(struct ti_bandgap *bgp, 1131eb982001SEduardo Valentin struct platform_device *pdev) 1132eb982001SEduardo Valentin { 1133eb982001SEduardo Valentin int gpio_nr = bgp->tshut_gpio; 1134eb982001SEduardo Valentin int status; 1135eb982001SEduardo Valentin 1136eb982001SEduardo Valentin /* Request for gpio_86 line */ 1137eb982001SEduardo Valentin status = gpio_request(gpio_nr, "tshut"); 1138eb982001SEduardo Valentin if (status < 0) { 1139eb982001SEduardo Valentin dev_err(bgp->dev, "Could not request for TSHUT GPIO:%i\n", 86); 1140eb982001SEduardo Valentin return status; 1141eb982001SEduardo Valentin } 1142eb982001SEduardo Valentin status = gpio_direction_input(gpio_nr); 1143eb982001SEduardo Valentin if (status) { 1144eb982001SEduardo Valentin dev_err(bgp->dev, "Cannot set input TSHUT GPIO %d\n", gpio_nr); 1145eb982001SEduardo Valentin return status; 1146eb982001SEduardo Valentin } 1147eb982001SEduardo Valentin 1148eb982001SEduardo Valentin status = request_irq(gpio_to_irq(gpio_nr), ti_bandgap_tshut_irq_handler, 1149eb982001SEduardo Valentin IRQF_TRIGGER_RISING, "tshut", NULL); 1150eb982001SEduardo Valentin if (status) { 1151eb982001SEduardo Valentin gpio_free(gpio_nr); 1152eb982001SEduardo Valentin dev_err(bgp->dev, "request irq failed for TSHUT"); 1153eb982001SEduardo Valentin } 1154eb982001SEduardo Valentin 1155eb982001SEduardo Valentin return 0; 1156eb982001SEduardo Valentin } 1157eb982001SEduardo Valentin 1158eb982001SEduardo Valentin /** 1159eb982001SEduardo Valentin * ti_bandgap_alert_init() - setup and initialize talert handling 1160eb982001SEduardo Valentin * @bgp: pointer to struct ti_bandgap 1161eb982001SEduardo Valentin * @pdev: pointer to device struct platform_device 1162eb982001SEduardo Valentin * 1163eb982001SEduardo Valentin * Call this function only in case the bandgap features HAS(TALERT). 1164eb982001SEduardo Valentin * In this case, the driver needs to handle the TALERT signals as an IRQs. 1165eb982001SEduardo Valentin * TALERT is a normal IRQ and it is fired any time thresholds (hot or cold) 1166eb982001SEduardo Valentin * are violated. In these situation, the driver must reprogram the thresholds, 1167eb982001SEduardo Valentin * accordingly to specified policy. 1168eb982001SEduardo Valentin * 1169eb982001SEduardo Valentin * Return: 0 if no error, else return corresponding error. 1170eb982001SEduardo Valentin */ 1171eb982001SEduardo Valentin static int ti_bandgap_talert_init(struct ti_bandgap *bgp, 1172eb982001SEduardo Valentin struct platform_device *pdev) 1173eb982001SEduardo Valentin { 1174eb982001SEduardo Valentin int ret; 1175eb982001SEduardo Valentin 1176eb982001SEduardo Valentin bgp->irq = platform_get_irq(pdev, 0); 1177eb982001SEduardo Valentin if (bgp->irq < 0) { 1178eb982001SEduardo Valentin dev_err(&pdev->dev, "get_irq failed\n"); 1179eb982001SEduardo Valentin return bgp->irq; 1180eb982001SEduardo Valentin } 1181eb982001SEduardo Valentin ret = request_threaded_irq(bgp->irq, NULL, 1182eb982001SEduardo Valentin ti_bandgap_talert_irq_handler, 1183eb982001SEduardo Valentin IRQF_TRIGGER_HIGH | IRQF_ONESHOT, 1184eb982001SEduardo Valentin "talert", bgp); 1185eb982001SEduardo Valentin if (ret) { 1186eb982001SEduardo Valentin dev_err(&pdev->dev, "Request threaded irq failed.\n"); 1187eb982001SEduardo Valentin return ret; 1188eb982001SEduardo Valentin } 1189eb982001SEduardo Valentin 1190eb982001SEduardo Valentin return 0; 1191eb982001SEduardo Valentin } 1192eb982001SEduardo Valentin 1193eb982001SEduardo Valentin static const struct of_device_id of_ti_bandgap_match[]; 1194eb982001SEduardo Valentin /** 1195eb982001SEduardo Valentin * ti_bandgap_build() - parse DT and setup a struct ti_bandgap 1196eb982001SEduardo Valentin * @pdev: pointer to device struct platform_device 1197eb982001SEduardo Valentin * 1198eb982001SEduardo Valentin * Used to read the device tree properties accordingly to the bandgap 1199eb982001SEduardo Valentin * matching version. Based on bandgap version and its capabilities it 1200eb982001SEduardo Valentin * will build a struct ti_bandgap out of the required DT entries. 1201eb982001SEduardo Valentin * 1202eb982001SEduardo Valentin * Return: valid bandgap structure if successful, else returns ERR_PTR 1203eb982001SEduardo Valentin * return value must be verified with IS_ERR. 1204eb982001SEduardo Valentin */ 1205eb982001SEduardo Valentin static struct ti_bandgap *ti_bandgap_build(struct platform_device *pdev) 1206eb982001SEduardo Valentin { 1207eb982001SEduardo Valentin struct device_node *node = pdev->dev.of_node; 1208eb982001SEduardo Valentin const struct of_device_id *of_id; 1209eb982001SEduardo Valentin struct ti_bandgap *bgp; 1210eb982001SEduardo Valentin struct resource *res; 1211eb982001SEduardo Valentin int i; 1212eb982001SEduardo Valentin 1213eb982001SEduardo Valentin /* just for the sake */ 1214eb982001SEduardo Valentin if (!node) { 1215eb982001SEduardo Valentin dev_err(&pdev->dev, "no platform information available\n"); 1216eb982001SEduardo Valentin return ERR_PTR(-EINVAL); 1217eb982001SEduardo Valentin } 1218eb982001SEduardo Valentin 1219eb982001SEduardo Valentin bgp = devm_kzalloc(&pdev->dev, sizeof(*bgp), GFP_KERNEL); 1220eb982001SEduardo Valentin if (!bgp) { 1221eb982001SEduardo Valentin dev_err(&pdev->dev, "Unable to allocate mem for driver ref\n"); 1222eb982001SEduardo Valentin return ERR_PTR(-ENOMEM); 1223eb982001SEduardo Valentin } 1224eb982001SEduardo Valentin 1225eb982001SEduardo Valentin of_id = of_match_device(of_ti_bandgap_match, &pdev->dev); 1226eb982001SEduardo Valentin if (of_id) 1227eb982001SEduardo Valentin bgp->conf = of_id->data; 1228eb982001SEduardo Valentin 1229eb982001SEduardo Valentin /* register shadow for context save and restore */ 1230eb982001SEduardo Valentin bgp->regval = devm_kzalloc(&pdev->dev, sizeof(*bgp->regval) * 1231eb982001SEduardo Valentin bgp->conf->sensor_count, GFP_KERNEL); 1232fbe2ddcdSRickard Strandqvist if (!bgp->regval) { 1233eb982001SEduardo Valentin dev_err(&pdev->dev, "Unable to allocate mem for driver ref\n"); 1234eb982001SEduardo Valentin return ERR_PTR(-ENOMEM); 1235eb982001SEduardo Valentin } 1236eb982001SEduardo Valentin 1237eb982001SEduardo Valentin i = 0; 1238eb982001SEduardo Valentin do { 1239eb982001SEduardo Valentin void __iomem *chunk; 1240eb982001SEduardo Valentin 1241eb982001SEduardo Valentin res = platform_get_resource(pdev, IORESOURCE_MEM, i); 1242eb982001SEduardo Valentin if (!res) 1243eb982001SEduardo Valentin break; 1244eb982001SEduardo Valentin chunk = devm_ioremap_resource(&pdev->dev, res); 1245eb982001SEduardo Valentin if (i == 0) 1246eb982001SEduardo Valentin bgp->base = chunk; 1247eb982001SEduardo Valentin if (IS_ERR(chunk)) 1248eb982001SEduardo Valentin return ERR_CAST(chunk); 1249eb982001SEduardo Valentin 1250eb982001SEduardo Valentin i++; 1251eb982001SEduardo Valentin } while (res); 1252eb982001SEduardo Valentin 1253eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, TSHUT)) { 125457d16171SEduardo Valentin bgp->tshut_gpio = of_get_gpio(node, 0); 1255eb982001SEduardo Valentin if (!gpio_is_valid(bgp->tshut_gpio)) { 1256eb982001SEduardo Valentin dev_err(&pdev->dev, "invalid gpio for tshut (%d)\n", 1257eb982001SEduardo Valentin bgp->tshut_gpio); 1258eb982001SEduardo Valentin return ERR_PTR(-EINVAL); 1259eb982001SEduardo Valentin } 1260eb982001SEduardo Valentin } 1261eb982001SEduardo Valentin 1262eb982001SEduardo Valentin return bgp; 1263eb982001SEduardo Valentin } 1264eb982001SEduardo Valentin 1265eb982001SEduardo Valentin /*** Device driver call backs ***/ 1266eb982001SEduardo Valentin 1267eb982001SEduardo Valentin static 1268eb982001SEduardo Valentin int ti_bandgap_probe(struct platform_device *pdev) 1269eb982001SEduardo Valentin { 1270eb982001SEduardo Valentin struct ti_bandgap *bgp; 1271eb982001SEduardo Valentin int clk_rate, ret = 0, i; 1272eb982001SEduardo Valentin 1273eb982001SEduardo Valentin bgp = ti_bandgap_build(pdev); 12740c12b5acSEduardo Valentin if (IS_ERR(bgp)) { 1275eb982001SEduardo Valentin dev_err(&pdev->dev, "failed to fetch platform data\n"); 1276eb982001SEduardo Valentin return PTR_ERR(bgp); 1277eb982001SEduardo Valentin } 1278eb982001SEduardo Valentin bgp->dev = &pdev->dev; 1279eb982001SEduardo Valentin 1280eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, TSHUT)) { 1281eb982001SEduardo Valentin ret = ti_bandgap_tshut_init(bgp, pdev); 1282eb982001SEduardo Valentin if (ret) { 1283eb982001SEduardo Valentin dev_err(&pdev->dev, 1284eb982001SEduardo Valentin "failed to initialize system tshut IRQ\n"); 1285eb982001SEduardo Valentin return ret; 1286eb982001SEduardo Valentin } 1287eb982001SEduardo Valentin } 1288eb982001SEduardo Valentin 1289eb982001SEduardo Valentin bgp->fclock = clk_get(NULL, bgp->conf->fclock_name); 12900c12b5acSEduardo Valentin ret = IS_ERR(bgp->fclock); 1291eb982001SEduardo Valentin if (ret) { 1292eb982001SEduardo Valentin dev_err(&pdev->dev, "failed to request fclock reference\n"); 12930c12b5acSEduardo Valentin ret = PTR_ERR(bgp->fclock); 1294eb982001SEduardo Valentin goto free_irqs; 1295eb982001SEduardo Valentin } 1296eb982001SEduardo Valentin 1297eb982001SEduardo Valentin bgp->div_clk = clk_get(NULL, bgp->conf->div_ck_name); 12980c12b5acSEduardo Valentin ret = IS_ERR(bgp->div_clk); 1299eb982001SEduardo Valentin if (ret) { 1300eb982001SEduardo Valentin dev_err(&pdev->dev, 1301eb982001SEduardo Valentin "failed to request div_ts_ck clock ref\n"); 13020c12b5acSEduardo Valentin ret = PTR_ERR(bgp->div_clk); 1303eb982001SEduardo Valentin goto free_irqs; 1304eb982001SEduardo Valentin } 1305eb982001SEduardo Valentin 1306eb982001SEduardo Valentin for (i = 0; i < bgp->conf->sensor_count; i++) { 1307eb982001SEduardo Valentin struct temp_sensor_registers *tsr; 1308eb982001SEduardo Valentin u32 val; 1309eb982001SEduardo Valentin 1310eb982001SEduardo Valentin tsr = bgp->conf->sensors[i].registers; 1311eb982001SEduardo Valentin /* 1312eb982001SEduardo Valentin * check if the efuse has a non-zero value if not 1313eb982001SEduardo Valentin * it is an untrimmed sample and the temperatures 1314eb982001SEduardo Valentin * may not be accurate 1315eb982001SEduardo Valentin */ 1316eb982001SEduardo Valentin val = ti_bandgap_readl(bgp, tsr->bgap_efuse); 1317eb982001SEduardo Valentin if (ret || !val) 1318eb982001SEduardo Valentin dev_info(&pdev->dev, 1319eb982001SEduardo Valentin "Non-trimmed BGAP, Temp not accurate\n"); 1320eb982001SEduardo Valentin } 1321eb982001SEduardo Valentin 1322eb982001SEduardo Valentin clk_rate = clk_round_rate(bgp->div_clk, 1323eb982001SEduardo Valentin bgp->conf->sensors[0].ts_data->max_freq); 1324eb982001SEduardo Valentin if (clk_rate < bgp->conf->sensors[0].ts_data->min_freq || 1325c68789e5SPaul Walmsley clk_rate <= 0) { 1326eb982001SEduardo Valentin ret = -ENODEV; 1327eb982001SEduardo Valentin dev_err(&pdev->dev, "wrong clock rate (%d)\n", clk_rate); 1328eb982001SEduardo Valentin goto put_clks; 1329eb982001SEduardo Valentin } 1330eb982001SEduardo Valentin 1331eb982001SEduardo Valentin ret = clk_set_rate(bgp->div_clk, clk_rate); 1332eb982001SEduardo Valentin if (ret) 1333eb982001SEduardo Valentin dev_err(&pdev->dev, "Cannot re-set clock rate. Continuing\n"); 1334eb982001SEduardo Valentin 1335eb982001SEduardo Valentin bgp->clk_rate = clk_rate; 1336eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, CLK_CTRL)) 1337eb982001SEduardo Valentin clk_prepare_enable(bgp->fclock); 1338eb982001SEduardo Valentin 1339eb982001SEduardo Valentin 1340eb982001SEduardo Valentin spin_lock_init(&bgp->lock); 1341eb982001SEduardo Valentin bgp->dev = &pdev->dev; 1342eb982001SEduardo Valentin platform_set_drvdata(pdev, bgp); 1343eb982001SEduardo Valentin 1344eb982001SEduardo Valentin ti_bandgap_power(bgp, true); 1345eb982001SEduardo Valentin 1346eb982001SEduardo Valentin /* Set default counter to 1 for now */ 1347eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, COUNTER)) 1348eb982001SEduardo Valentin for (i = 0; i < bgp->conf->sensor_count; i++) 1349eb982001SEduardo Valentin RMW_BITS(bgp, i, bgap_counter, counter_mask, 1); 1350eb982001SEduardo Valentin 1351eb982001SEduardo Valentin /* Set default thresholds for alert and shutdown */ 1352eb982001SEduardo Valentin for (i = 0; i < bgp->conf->sensor_count; i++) { 1353eb982001SEduardo Valentin struct temp_sensor_data *ts_data; 1354eb982001SEduardo Valentin 1355eb982001SEduardo Valentin ts_data = bgp->conf->sensors[i].ts_data; 1356eb982001SEduardo Valentin 1357eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, TALERT)) { 1358eb982001SEduardo Valentin /* Set initial Talert thresholds */ 1359eb982001SEduardo Valentin RMW_BITS(bgp, i, bgap_threshold, 1360eb982001SEduardo Valentin threshold_tcold_mask, ts_data->t_cold); 1361eb982001SEduardo Valentin RMW_BITS(bgp, i, bgap_threshold, 1362eb982001SEduardo Valentin threshold_thot_mask, ts_data->t_hot); 1363eb982001SEduardo Valentin /* Enable the alert events */ 1364eb982001SEduardo Valentin RMW_BITS(bgp, i, bgap_mask_ctrl, mask_hot_mask, 1); 1365eb982001SEduardo Valentin RMW_BITS(bgp, i, bgap_mask_ctrl, mask_cold_mask, 1); 1366eb982001SEduardo Valentin } 1367eb982001SEduardo Valentin 1368eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG)) { 1369eb982001SEduardo Valentin /* Set initial Tshut thresholds */ 1370eb982001SEduardo Valentin RMW_BITS(bgp, i, tshut_threshold, 1371eb982001SEduardo Valentin tshut_hot_mask, ts_data->tshut_hot); 1372eb982001SEduardo Valentin RMW_BITS(bgp, i, tshut_threshold, 1373eb982001SEduardo Valentin tshut_cold_mask, ts_data->tshut_cold); 1374eb982001SEduardo Valentin } 1375eb982001SEduardo Valentin } 1376eb982001SEduardo Valentin 1377eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, MODE_CONFIG)) 1378eb982001SEduardo Valentin ti_bandgap_set_continuous_mode(bgp); 1379eb982001SEduardo Valentin 1380eb982001SEduardo Valentin /* Set .250 seconds time as default counter */ 1381eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, COUNTER)) 1382eb982001SEduardo Valentin for (i = 0; i < bgp->conf->sensor_count; i++) 1383eb982001SEduardo Valentin RMW_BITS(bgp, i, bgap_counter, counter_mask, 1384eb982001SEduardo Valentin bgp->clk_rate / 4); 1385eb982001SEduardo Valentin 1386eb982001SEduardo Valentin /* Every thing is good? Then expose the sensors */ 1387eb982001SEduardo Valentin for (i = 0; i < bgp->conf->sensor_count; i++) { 1388eb982001SEduardo Valentin char *domain; 1389eb982001SEduardo Valentin 1390eb982001SEduardo Valentin if (bgp->conf->sensors[i].register_cooling) { 1391eb982001SEduardo Valentin ret = bgp->conf->sensors[i].register_cooling(bgp, i); 1392eb982001SEduardo Valentin if (ret) 1393eb982001SEduardo Valentin goto remove_sensors; 1394eb982001SEduardo Valentin } 1395eb982001SEduardo Valentin 1396eb982001SEduardo Valentin if (bgp->conf->expose_sensor) { 1397eb982001SEduardo Valentin domain = bgp->conf->sensors[i].domain; 1398eb982001SEduardo Valentin ret = bgp->conf->expose_sensor(bgp, i, domain); 1399eb982001SEduardo Valentin if (ret) 1400eb982001SEduardo Valentin goto remove_last_cooling; 1401eb982001SEduardo Valentin } 1402eb982001SEduardo Valentin } 1403eb982001SEduardo Valentin 1404eb982001SEduardo Valentin /* 1405eb982001SEduardo Valentin * Enable the Interrupts once everything is set. Otherwise irq handler 1406eb982001SEduardo Valentin * might be called as soon as it is enabled where as rest of framework 1407eb982001SEduardo Valentin * is still getting initialised. 1408eb982001SEduardo Valentin */ 1409eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, TALERT)) { 1410eb982001SEduardo Valentin ret = ti_bandgap_talert_init(bgp, pdev); 1411eb982001SEduardo Valentin if (ret) { 1412eb982001SEduardo Valentin dev_err(&pdev->dev, "failed to initialize Talert IRQ\n"); 1413eb982001SEduardo Valentin i = bgp->conf->sensor_count; 1414eb982001SEduardo Valentin goto disable_clk; 1415eb982001SEduardo Valentin } 1416eb982001SEduardo Valentin } 1417eb982001SEduardo Valentin 1418eb982001SEduardo Valentin return 0; 1419eb982001SEduardo Valentin 1420eb982001SEduardo Valentin remove_last_cooling: 1421eb982001SEduardo Valentin if (bgp->conf->sensors[i].unregister_cooling) 1422eb982001SEduardo Valentin bgp->conf->sensors[i].unregister_cooling(bgp, i); 1423eb982001SEduardo Valentin remove_sensors: 1424eb982001SEduardo Valentin for (i--; i >= 0; i--) { 1425eb982001SEduardo Valentin if (bgp->conf->sensors[i].unregister_cooling) 1426eb982001SEduardo Valentin bgp->conf->sensors[i].unregister_cooling(bgp, i); 1427eb982001SEduardo Valentin if (bgp->conf->remove_sensor) 1428eb982001SEduardo Valentin bgp->conf->remove_sensor(bgp, i); 1429eb982001SEduardo Valentin } 1430eb982001SEduardo Valentin ti_bandgap_power(bgp, false); 1431eb982001SEduardo Valentin disable_clk: 1432eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, CLK_CTRL)) 1433eb982001SEduardo Valentin clk_disable_unprepare(bgp->fclock); 1434eb982001SEduardo Valentin put_clks: 1435eb982001SEduardo Valentin clk_put(bgp->fclock); 1436eb982001SEduardo Valentin clk_put(bgp->div_clk); 1437eb982001SEduardo Valentin free_irqs: 1438eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, TSHUT)) { 1439eb982001SEduardo Valentin free_irq(gpio_to_irq(bgp->tshut_gpio), NULL); 1440eb982001SEduardo Valentin gpio_free(bgp->tshut_gpio); 1441eb982001SEduardo Valentin } 1442eb982001SEduardo Valentin 1443eb982001SEduardo Valentin return ret; 1444eb982001SEduardo Valentin } 1445eb982001SEduardo Valentin 1446eb982001SEduardo Valentin static 1447eb982001SEduardo Valentin int ti_bandgap_remove(struct platform_device *pdev) 1448eb982001SEduardo Valentin { 1449eb982001SEduardo Valentin struct ti_bandgap *bgp = platform_get_drvdata(pdev); 1450eb982001SEduardo Valentin int i; 1451eb982001SEduardo Valentin 1452eb982001SEduardo Valentin /* First thing is to remove sensor interfaces */ 1453eb982001SEduardo Valentin for (i = 0; i < bgp->conf->sensor_count; i++) { 1454eb982001SEduardo Valentin if (bgp->conf->sensors[i].unregister_cooling) 1455eb982001SEduardo Valentin bgp->conf->sensors[i].unregister_cooling(bgp, i); 1456eb982001SEduardo Valentin 1457eb982001SEduardo Valentin if (bgp->conf->remove_sensor) 1458eb982001SEduardo Valentin bgp->conf->remove_sensor(bgp, i); 1459eb982001SEduardo Valentin } 1460eb982001SEduardo Valentin 1461eb982001SEduardo Valentin ti_bandgap_power(bgp, false); 1462eb982001SEduardo Valentin 1463eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, CLK_CTRL)) 1464eb982001SEduardo Valentin clk_disable_unprepare(bgp->fclock); 1465eb982001SEduardo Valentin clk_put(bgp->fclock); 1466eb982001SEduardo Valentin clk_put(bgp->div_clk); 1467eb982001SEduardo Valentin 1468eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, TALERT)) 1469eb982001SEduardo Valentin free_irq(bgp->irq, bgp); 1470eb982001SEduardo Valentin 1471eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, TSHUT)) { 1472eb982001SEduardo Valentin free_irq(gpio_to_irq(bgp->tshut_gpio), NULL); 1473eb982001SEduardo Valentin gpio_free(bgp->tshut_gpio); 1474eb982001SEduardo Valentin } 1475eb982001SEduardo Valentin 1476eb982001SEduardo Valentin return 0; 1477eb982001SEduardo Valentin } 1478eb982001SEduardo Valentin 14793992b62dSGrygorii Strashko #ifdef CONFIG_PM_SLEEP 1480eb982001SEduardo Valentin static int ti_bandgap_save_ctxt(struct ti_bandgap *bgp) 1481eb982001SEduardo Valentin { 1482eb982001SEduardo Valentin int i; 1483eb982001SEduardo Valentin 1484eb982001SEduardo Valentin for (i = 0; i < bgp->conf->sensor_count; i++) { 1485eb982001SEduardo Valentin struct temp_sensor_registers *tsr; 1486eb982001SEduardo Valentin struct temp_sensor_regval *rval; 1487eb982001SEduardo Valentin 1488eb982001SEduardo Valentin rval = &bgp->regval[i]; 1489eb982001SEduardo Valentin tsr = bgp->conf->sensors[i].registers; 1490eb982001SEduardo Valentin 1491eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, MODE_CONFIG)) 1492eb982001SEduardo Valentin rval->bg_mode_ctrl = ti_bandgap_readl(bgp, 1493eb982001SEduardo Valentin tsr->bgap_mode_ctrl); 1494eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, COUNTER)) 1495eb982001SEduardo Valentin rval->bg_counter = ti_bandgap_readl(bgp, 1496eb982001SEduardo Valentin tsr->bgap_counter); 1497eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, TALERT)) { 1498eb982001SEduardo Valentin rval->bg_threshold = ti_bandgap_readl(bgp, 1499eb982001SEduardo Valentin tsr->bgap_threshold); 1500eb982001SEduardo Valentin rval->bg_ctrl = ti_bandgap_readl(bgp, 1501eb982001SEduardo Valentin tsr->bgap_mask_ctrl); 1502eb982001SEduardo Valentin } 1503eb982001SEduardo Valentin 1504eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG)) 1505eb982001SEduardo Valentin rval->tshut_threshold = ti_bandgap_readl(bgp, 1506eb982001SEduardo Valentin tsr->tshut_threshold); 1507eb982001SEduardo Valentin } 1508eb982001SEduardo Valentin 1509eb982001SEduardo Valentin return 0; 1510eb982001SEduardo Valentin } 1511eb982001SEduardo Valentin 1512eb982001SEduardo Valentin static int ti_bandgap_restore_ctxt(struct ti_bandgap *bgp) 1513eb982001SEduardo Valentin { 1514eb982001SEduardo Valentin int i; 1515eb982001SEduardo Valentin 1516eb982001SEduardo Valentin for (i = 0; i < bgp->conf->sensor_count; i++) { 1517eb982001SEduardo Valentin struct temp_sensor_registers *tsr; 1518eb982001SEduardo Valentin struct temp_sensor_regval *rval; 1519eb982001SEduardo Valentin u32 val = 0; 1520eb982001SEduardo Valentin 1521eb982001SEduardo Valentin rval = &bgp->regval[i]; 1522eb982001SEduardo Valentin tsr = bgp->conf->sensors[i].registers; 1523eb982001SEduardo Valentin 1524eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, COUNTER)) 1525eb982001SEduardo Valentin val = ti_bandgap_readl(bgp, tsr->bgap_counter); 1526eb982001SEduardo Valentin 1527eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG)) 1528eb982001SEduardo Valentin ti_bandgap_writel(bgp, rval->tshut_threshold, 1529eb982001SEduardo Valentin tsr->tshut_threshold); 1530eb982001SEduardo Valentin /* Force immediate temperature measurement and update 1531eb982001SEduardo Valentin * of the DTEMP field 1532eb982001SEduardo Valentin */ 1533eb982001SEduardo Valentin ti_bandgap_force_single_read(bgp, i); 1534eb982001SEduardo Valentin 1535eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, COUNTER)) 1536eb982001SEduardo Valentin ti_bandgap_writel(bgp, rval->bg_counter, 1537eb982001SEduardo Valentin tsr->bgap_counter); 1538eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, MODE_CONFIG)) 1539eb982001SEduardo Valentin ti_bandgap_writel(bgp, rval->bg_mode_ctrl, 1540eb982001SEduardo Valentin tsr->bgap_mode_ctrl); 1541eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, TALERT)) { 1542eb982001SEduardo Valentin ti_bandgap_writel(bgp, rval->bg_threshold, 1543eb982001SEduardo Valentin tsr->bgap_threshold); 1544eb982001SEduardo Valentin ti_bandgap_writel(bgp, rval->bg_ctrl, 1545eb982001SEduardo Valentin tsr->bgap_mask_ctrl); 1546eb982001SEduardo Valentin } 1547eb982001SEduardo Valentin } 1548eb982001SEduardo Valentin 1549eb982001SEduardo Valentin return 0; 1550eb982001SEduardo Valentin } 1551eb982001SEduardo Valentin 1552eb982001SEduardo Valentin static int ti_bandgap_suspend(struct device *dev) 1553eb982001SEduardo Valentin { 1554eb982001SEduardo Valentin struct ti_bandgap *bgp = dev_get_drvdata(dev); 1555eb982001SEduardo Valentin int err; 1556eb982001SEduardo Valentin 1557eb982001SEduardo Valentin err = ti_bandgap_save_ctxt(bgp); 1558eb982001SEduardo Valentin ti_bandgap_power(bgp, false); 1559eb982001SEduardo Valentin 1560eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, CLK_CTRL)) 1561eb982001SEduardo Valentin clk_disable_unprepare(bgp->fclock); 1562eb982001SEduardo Valentin 1563eb982001SEduardo Valentin return err; 1564eb982001SEduardo Valentin } 1565eb982001SEduardo Valentin 1566eb982001SEduardo Valentin static int ti_bandgap_resume(struct device *dev) 1567eb982001SEduardo Valentin { 1568eb982001SEduardo Valentin struct ti_bandgap *bgp = dev_get_drvdata(dev); 1569eb982001SEduardo Valentin 1570eb982001SEduardo Valentin if (TI_BANDGAP_HAS(bgp, CLK_CTRL)) 1571eb982001SEduardo Valentin clk_prepare_enable(bgp->fclock); 1572eb982001SEduardo Valentin 1573eb982001SEduardo Valentin ti_bandgap_power(bgp, true); 1574eb982001SEduardo Valentin 1575eb982001SEduardo Valentin return ti_bandgap_restore_ctxt(bgp); 1576eb982001SEduardo Valentin } 15775204f8c0SJingoo Han static SIMPLE_DEV_PM_OPS(ti_bandgap_dev_pm_ops, ti_bandgap_suspend, 15785204f8c0SJingoo Han ti_bandgap_resume); 1579eb982001SEduardo Valentin 1580eb982001SEduardo Valentin #define DEV_PM_OPS (&ti_bandgap_dev_pm_ops) 1581eb982001SEduardo Valentin #else 1582eb982001SEduardo Valentin #define DEV_PM_OPS NULL 1583eb982001SEduardo Valentin #endif 1584eb982001SEduardo Valentin 1585eb982001SEduardo Valentin static const struct of_device_id of_ti_bandgap_match[] = { 1586eb982001SEduardo Valentin #ifdef CONFIG_OMAP4_THERMAL 1587eb982001SEduardo Valentin { 1588eb982001SEduardo Valentin .compatible = "ti,omap4430-bandgap", 1589eb982001SEduardo Valentin .data = (void *)&omap4430_data, 1590eb982001SEduardo Valentin }, 1591eb982001SEduardo Valentin { 1592eb982001SEduardo Valentin .compatible = "ti,omap4460-bandgap", 1593eb982001SEduardo Valentin .data = (void *)&omap4460_data, 1594eb982001SEduardo Valentin }, 1595eb982001SEduardo Valentin { 1596eb982001SEduardo Valentin .compatible = "ti,omap4470-bandgap", 1597eb982001SEduardo Valentin .data = (void *)&omap4470_data, 1598eb982001SEduardo Valentin }, 1599eb982001SEduardo Valentin #endif 1600eb982001SEduardo Valentin #ifdef CONFIG_OMAP5_THERMAL 1601eb982001SEduardo Valentin { 1602eb982001SEduardo Valentin .compatible = "ti,omap5430-bandgap", 1603eb982001SEduardo Valentin .data = (void *)&omap5430_data, 1604eb982001SEduardo Valentin }, 1605eb982001SEduardo Valentin #endif 160625870e62SEduardo Valentin #ifdef CONFIG_DRA752_THERMAL 160725870e62SEduardo Valentin { 160825870e62SEduardo Valentin .compatible = "ti,dra752-bandgap", 160925870e62SEduardo Valentin .data = (void *)&dra752_data, 161025870e62SEduardo Valentin }, 161125870e62SEduardo Valentin #endif 1612eb982001SEduardo Valentin /* Sentinel */ 1613eb982001SEduardo Valentin { }, 1614eb982001SEduardo Valentin }; 1615eb982001SEduardo Valentin MODULE_DEVICE_TABLE(of, of_ti_bandgap_match); 1616eb982001SEduardo Valentin 1617eb982001SEduardo Valentin static struct platform_driver ti_bandgap_sensor_driver = { 1618eb982001SEduardo Valentin .probe = ti_bandgap_probe, 1619eb982001SEduardo Valentin .remove = ti_bandgap_remove, 1620eb982001SEduardo Valentin .driver = { 1621eb982001SEduardo Valentin .name = "ti-soc-thermal", 1622eb982001SEduardo Valentin .pm = DEV_PM_OPS, 1623eb982001SEduardo Valentin .of_match_table = of_ti_bandgap_match, 1624eb982001SEduardo Valentin }, 1625eb982001SEduardo Valentin }; 1626eb982001SEduardo Valentin 1627eb982001SEduardo Valentin module_platform_driver(ti_bandgap_sensor_driver); 1628eb982001SEduardo Valentin 1629eb982001SEduardo Valentin MODULE_DESCRIPTION("OMAP4+ bandgap temperature sensor driver"); 1630eb982001SEduardo Valentin MODULE_LICENSE("GPL v2"); 1631eb982001SEduardo Valentin MODULE_ALIAS("platform:ti-soc-thermal"); 1632eb982001SEduardo Valentin MODULE_AUTHOR("Texas Instrument Inc."); 1633