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