staging: omap-thermal: add documentation for omap_bandgap_mcelsius_to_adc
[linux-block.git] / drivers / staging / omap-thermal / omap-bandgap.c
1 /*
2  * OMAP4 Bandgap temperature sensor driver
3  *
4  * Copyright (C) 2011-2012 Texas Instruments Incorporated - http://www.ti.com/
5  * Author: J Keerthy <j-keerthy@ti.com>
6  * Author: Moiz Sonasath <m-sonasath@ti.com>
7  * Couple of fixes, DT and MFD adaptation:
8  *   Eduardo Valentin <eduardo.valentin@ti.com>
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * version 2 as published by the Free Software Foundation.
13  *
14  * This program is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22  * 02110-1301 USA
23  *
24  */
25
26 #include <linux/module.h>
27 #include <linux/export.h>
28 #include <linux/init.h>
29 #include <linux/kernel.h>
30 #include <linux/interrupt.h>
31 #include <linux/clk.h>
32 #include <linux/gpio.h>
33 #include <linux/platform_device.h>
34 #include <linux/err.h>
35 #include <linux/types.h>
36 #include <linux/mutex.h>
37 #include <linux/reboot.h>
38 #include <linux/of_device.h>
39 #include <linux/of_platform.h>
40 #include <linux/of_irq.h>
41 #include <linux/io.h>
42
43 #include "omap-bandgap.h"
44
45 /***   Helper functions to access registers and their bitfields   ***/
46
47 /**
48  * omap_bandgap_readl() - simple read helper function
49  * @bg_ptr: pointer to omap_bandgap structure
50  * @reg: desired register (offset) to be read
51  *
52  * Helper function to read bandgap registers. It uses the io remapped area.
53  * Returns the register value.
54  */
55 static u32 omap_bandgap_readl(struct omap_bandgap *bg_ptr, u32 reg)
56 {
57         return readl(bg_ptr->base + reg);
58 }
59
60 /**
61  * omap_bandgap_writel() - simple write helper function
62  * @bg_ptr: pointer to omap_bandgap structure
63  * @val: desired register value to be written
64  * @reg: desired register (offset) to be written
65  *
66  * Helper function to write bandgap registers. It uses the io remapped area.
67  */
68 static void omap_bandgap_writel(struct omap_bandgap *bg_ptr, u32 val, u32 reg)
69 {
70         writel(val, bg_ptr->base + reg);
71 }
72
73 /**
74  * DOC: macro to update bits.
75  *
76  * RMW_BITS() - used to read, modify and update bandgap bitfields.
77  *            The value passed will be shifted.
78  */
79 #define RMW_BITS(bg_ptr, id, reg, mask, val)                    \
80 do {                                                            \
81         struct temp_sensor_registers *t;                        \
82         u32 r;                                                  \
83                                                                 \
84         t = bg_ptr->conf->sensors[(id)].registers;              \
85         r = omap_bandgap_readl(bg_ptr, t->reg);                 \
86         r &= ~t->mask;                                          \
87         r |= (val) << __ffs(t->mask);                           \
88         omap_bandgap_writel(bg_ptr, r, t->reg);                 \
89 } while (0)
90
91 /***   Basic helper functions   ***/
92
93 /**
94  * omap_bandgap_power() - controls the power state of a bandgap device
95  * @bg_ptr: pointer to omap_bandgap structure
96  * @on: desired power state (1 - on, 0 - off)
97  *
98  * Used to power on/off a bandgap device instance. Only used on those
99  * that features tempsoff bit.
100  */
101 static int omap_bandgap_power(struct omap_bandgap *bg_ptr, bool on)
102 {
103         int i;
104
105         if (!OMAP_BANDGAP_HAS(bg_ptr, POWER_SWITCH))
106                 goto exit;
107
108         for (i = 0; i < bg_ptr->conf->sensor_count; i++)
109                 /* active on 0 */
110                 RMW_BITS(bg_ptr, i, temp_sensor_ctrl, bgap_tempsoff_mask, !on);
111
112 exit:
113         return 0;
114 }
115
116 /**
117  * omap_bandgap_read_temp() - helper function to read sensor temperature
118  * @bg_ptr: pointer to omap_bandgap structure
119  * @id: bandgap sensor id
120  *
121  * Function to concentrate the steps to read sensor temperature register.
122  * This function is desired because, depending on bandgap device version,
123  * it might be needed to freeze the bandgap state machine, before fetching
124  * the register value.
125  */
126 static u32 omap_bandgap_read_temp(struct omap_bandgap *bg_ptr, int id)
127 {
128         struct temp_sensor_registers *tsr;
129         u32 temp, reg;
130
131         tsr = bg_ptr->conf->sensors[id].registers;
132         reg = tsr->temp_sensor_ctrl;
133
134         if (OMAP_BANDGAP_HAS(bg_ptr, FREEZE_BIT)) {
135                 RMW_BITS(bg_ptr, id, bgap_mask_ctrl, mask_freeze_mask, 1);
136                 /*
137                  * In case we cannot read from cur_dtemp / dtemp_0,
138                  * then we read from the last valid temp read
139                  */
140                 reg = tsr->ctrl_dtemp_1;
141         }
142
143         /* read temperature */
144         temp = omap_bandgap_readl(bg_ptr, reg);
145         temp &= tsr->bgap_dtemp_mask;
146
147         if (OMAP_BANDGAP_HAS(bg_ptr, FREEZE_BIT))
148                 RMW_BITS(bg_ptr, id, bgap_mask_ctrl, mask_freeze_mask, 0);
149
150         return temp;
151 }
152
153 /***   IRQ handlers   ***/
154
155 /**
156  * omap_bandgap_talert_irq_handler() - handles Temperature alert IRQs
157  * @irq: IRQ number
158  * @data: private data (struct omap_bandgap *)
159  *
160  * This is the Talert handler. Use it only if bandgap device features
161  * HAS(TALERT). This handler goes over all sensors and checks their
162  * conditions and acts accordingly. In case there are events pending,
163  * it will reset the event mask to wait for the opposite event (next event).
164  * Every time there is a new event, it will be reported to thermal layer.
165  */
166 static irqreturn_t omap_bandgap_talert_irq_handler(int irq, void *data)
167 {
168         struct omap_bandgap *bg_ptr = data;
169         struct temp_sensor_registers *tsr;
170         u32 t_hot = 0, t_cold = 0, ctrl;
171         int i;
172
173         for (i = 0; i < bg_ptr->conf->sensor_count; i++) {
174                 tsr = bg_ptr->conf->sensors[i].registers;
175                 ctrl = omap_bandgap_readl(bg_ptr, tsr->bgap_status);
176
177                 /* Read the status of t_hot */
178                 t_hot = ctrl & tsr->status_hot_mask;
179
180                 /* Read the status of t_cold */
181                 t_cold = ctrl & tsr->status_cold_mask;
182
183                 if (!t_cold && !t_hot)
184                         continue;
185
186                 ctrl = omap_bandgap_readl(bg_ptr, tsr->bgap_mask_ctrl);
187                 /*
188                  * One TALERT interrupt: Two sources
189                  * If the interrupt is due to t_hot then mask t_hot and
190                  * and unmask t_cold else mask t_cold and unmask t_hot
191                  */
192                 if (t_hot) {
193                         ctrl &= ~tsr->mask_hot_mask;
194                         ctrl |= tsr->mask_cold_mask;
195                 } else if (t_cold) {
196                         ctrl &= ~tsr->mask_cold_mask;
197                         ctrl |= tsr->mask_hot_mask;
198                 }
199
200                 omap_bandgap_writel(bg_ptr, ctrl, tsr->bgap_mask_ctrl);
201
202                 dev_dbg(bg_ptr->dev,
203                         "%s: IRQ from %s sensor: hotevent %d coldevent %d\n",
204                         __func__, bg_ptr->conf->sensors[i].domain,
205                         t_hot, t_cold);
206
207                 /* report temperature to whom may concern */
208                 if (bg_ptr->conf->report_temperature)
209                         bg_ptr->conf->report_temperature(bg_ptr, i);
210         }
211
212         return IRQ_HANDLED;
213 }
214
215 /**
216  * omap_bandgap_tshut_irq_handler() - handles Temperature shutdown signal
217  * @irq: IRQ number
218  * @data: private data (unused)
219  *
220  * This is the Tshut handler. Use it only if bandgap device features
221  * HAS(TSHUT). If any sensor fires the Tshut signal, we simply shutdown
222  * the system.
223  */
224 static irqreturn_t omap_bandgap_tshut_irq_handler(int irq, void *data)
225 {
226         pr_emerg("%s: TSHUT temperature reached. Needs shut down...\n",
227                  __func__);
228
229         orderly_poweroff(true);
230
231         return IRQ_HANDLED;
232 }
233
234 /***   Helper functions which manipulate conversion ADC <-> mi Celsius   ***/
235
236 /**
237  * omap_bandgap_adc_to_mcelsius() - converts an ADC value to mCelsius scale
238  * @bg_ptr: struct omap_bandgap pointer
239  * @adc_val: value in ADC representation
240  * @t: address where to write the resulting temperature in mCelsius
241  *
242  * Simple conversion from ADC representation to mCelsius. In case the ADC value
243  * is out of the ADC conv table range, it returns -ERANGE, 0 on success.
244  * The conversion table is indexed by the ADC values.
245  */
246 static
247 int omap_bandgap_adc_to_mcelsius(struct omap_bandgap *bg_ptr,
248                                  int adc_val, int *t)
249 {
250         struct omap_bandgap_data *conf = bg_ptr->conf;
251         int ret = 0;
252
253         /* look up for temperature in the table and return the temperature */
254         if (adc_val < conf->adc_start_val || adc_val > conf->adc_end_val) {
255                 ret = -ERANGE;
256                 goto exit;
257         }
258
259         *t = bg_ptr->conf->conv_table[adc_val - conf->adc_start_val];
260
261 exit:
262         return ret;
263 }
264
265 /**
266  * omap_bandgap_mcelsius_to_adc() - converts a mCelsius value to ADC scale
267  * @bg_ptr: struct omap_bandgap pointer
268  * @temp: value in mCelsius
269  * @adc: address where to write the resulting temperature in ADC representation
270  *
271  * Simple conversion from mCelsius to ADC values. In case the temp value
272  * is out of the ADC conv table range, it returns -ERANGE, 0 on success.
273  * The conversion table is indexed by the ADC values.
274  */
275 static
276 int omap_bandgap_mcelsius_to_adc(struct omap_bandgap *bg_ptr, long temp,
277                                  int *adc)
278 {
279         struct omap_bandgap_data *conf = bg_ptr->conf;
280         const int *conv_table = bg_ptr->conf->conv_table;
281         int high, low, mid, ret = 0;
282
283         low = 0;
284         high = conf->adc_end_val - conf->adc_start_val;
285         mid = (high + low) / 2;
286
287         if (temp < conv_table[low] || temp > conv_table[high]) {
288                 ret = -ERANGE;
289                 goto exit;
290         }
291
292         while (low < high) {
293                 if (temp < conv_table[mid])
294                         high = mid - 1;
295                 else
296                         low = mid + 1;
297                 mid = (low + high) / 2;
298         }
299
300         *adc = conf->adc_start_val + low;
301
302 exit:
303         return ret;
304 }
305
306 /* Talert masks. Call it only if HAS(TALERT) is set */
307 static int temp_sensor_unmask_interrupts(struct omap_bandgap *bg_ptr, int id,
308                                          u32 t_hot, u32 t_cold)
309 {
310         struct temp_sensor_registers *tsr;
311         u32 temp, reg_val;
312
313         /* Read the current on die temperature */
314         temp = omap_bandgap_read_temp(bg_ptr, id);
315
316         tsr = bg_ptr->conf->sensors[id].registers;
317         reg_val = omap_bandgap_readl(bg_ptr, tsr->bgap_mask_ctrl);
318
319         if (temp < t_hot)
320                 reg_val |= tsr->mask_hot_mask;
321         else
322                 reg_val &= ~tsr->mask_hot_mask;
323
324         if (t_cold < temp)
325                 reg_val |= tsr->mask_cold_mask;
326         else
327                 reg_val &= ~tsr->mask_cold_mask;
328         omap_bandgap_writel(bg_ptr, reg_val, tsr->bgap_mask_ctrl);
329
330         return 0;
331 }
332
333 static
334 int add_hyst(int adc_val, int hyst_val, struct omap_bandgap *bg_ptr, u32 *sum)
335 {
336         int temp, ret;
337
338         ret = omap_bandgap_adc_to_mcelsius(bg_ptr, adc_val, &temp);
339         if (ret < 0)
340                 return ret;
341
342         temp += hyst_val;
343
344         return omap_bandgap_mcelsius_to_adc(bg_ptr, temp, sum);
345 }
346
347 /* Talert Thot threshold. Call it only if HAS(TALERT) is set */
348 static
349 int temp_sensor_configure_thot(struct omap_bandgap *bg_ptr, int id, int t_hot)
350 {
351         struct temp_sensor_data *ts_data = bg_ptr->conf->sensors[id].ts_data;
352         struct temp_sensor_registers *tsr;
353         u32 thresh_val, reg_val;
354         int cold, err = 0;
355
356         tsr = bg_ptr->conf->sensors[id].registers;
357
358         /* obtain the T cold value */
359         thresh_val = omap_bandgap_readl(bg_ptr, tsr->bgap_threshold);
360         cold = (thresh_val & tsr->threshold_tcold_mask) >>
361             __ffs(tsr->threshold_tcold_mask);
362         if (t_hot <= cold) {
363                 /* change the t_cold to t_hot - 5000 millidegrees */
364                 err |= add_hyst(t_hot, -ts_data->hyst_val, bg_ptr, &cold);
365                 /* write the new t_cold value */
366                 reg_val = thresh_val & (~tsr->threshold_tcold_mask);
367                 reg_val |= cold << __ffs(tsr->threshold_tcold_mask);
368                 omap_bandgap_writel(bg_ptr, reg_val, tsr->bgap_threshold);
369                 thresh_val = reg_val;
370         }
371
372         /* write the new t_hot value */
373         reg_val = thresh_val & ~tsr->threshold_thot_mask;
374         reg_val |= (t_hot << __ffs(tsr->threshold_thot_mask));
375         omap_bandgap_writel(bg_ptr, reg_val, tsr->bgap_threshold);
376         if (err) {
377                 dev_err(bg_ptr->dev, "failed to reprogram thot threshold\n");
378                 return -EIO;
379         }
380
381         return temp_sensor_unmask_interrupts(bg_ptr, id, t_hot, cold);
382 }
383
384 /* Talert Tcold threshold. Call it only if HAS(TALERT) is set */
385 static
386 int temp_sensor_configure_tcold(struct omap_bandgap *bg_ptr, int id,
387                                 int t_cold)
388 {
389         struct temp_sensor_data *ts_data = bg_ptr->conf->sensors[id].ts_data;
390         struct temp_sensor_registers *tsr;
391         u32 thresh_val, reg_val;
392         int hot, err = 0;
393
394         tsr = bg_ptr->conf->sensors[id].registers;
395         /* obtain the T cold value */
396         thresh_val = omap_bandgap_readl(bg_ptr, tsr->bgap_threshold);
397         hot = (thresh_val & tsr->threshold_thot_mask) >>
398             __ffs(tsr->threshold_thot_mask);
399
400         if (t_cold >= hot) {
401                 /* change the t_hot to t_cold + 5000 millidegrees */
402                 err |= add_hyst(t_cold, ts_data->hyst_val, bg_ptr, &hot);
403                 /* write the new t_hot value */
404                 reg_val = thresh_val & (~tsr->threshold_thot_mask);
405                 reg_val |= hot << __ffs(tsr->threshold_thot_mask);
406                 omap_bandgap_writel(bg_ptr, reg_val, tsr->bgap_threshold);
407                 thresh_val = reg_val;
408         }
409
410         /* write the new t_cold value */
411         reg_val = thresh_val & ~tsr->threshold_tcold_mask;
412         reg_val |= (t_cold << __ffs(tsr->threshold_tcold_mask));
413         omap_bandgap_writel(bg_ptr, reg_val, tsr->bgap_threshold);
414         if (err) {
415                 dev_err(bg_ptr->dev, "failed to reprogram tcold threshold\n");
416                 return -EIO;
417         }
418
419         return temp_sensor_unmask_interrupts(bg_ptr, id, hot, t_cold);
420 }
421
422 #define bandgap_is_valid(b)                                             \
423                         (!IS_ERR_OR_NULL(b))
424 #define bandgap_is_valid_sensor_id(b, i)                                \
425                         ((i) >= 0 && (i) < (b)->conf->sensor_count)
426 static inline int omap_bandgap_validate(struct omap_bandgap *bg_ptr, int id)
427 {
428         if (!bandgap_is_valid(bg_ptr)) {
429                 pr_err("%s: invalid bandgap pointer\n", __func__);
430                 return -EINVAL;
431         }
432
433         if (!bandgap_is_valid_sensor_id(bg_ptr, id)) {
434                 dev_err(bg_ptr->dev, "%s: sensor id out of range (%d)\n",
435                         __func__, id);
436                 return -ERANGE;
437         }
438
439         return 0;
440 }
441
442 /* Exposed APIs */
443 /**
444  * omap_bandgap_read_thot() - reads sensor current thot
445  * @bg_ptr - pointer to bandgap instance
446  * @id - sensor id
447  * @thot - resulting current thot value
448  *
449  * returns 0 on success or the proper error code
450  */
451 int omap_bandgap_read_thot(struct omap_bandgap *bg_ptr, int id,
452                            int *thot)
453 {
454         struct temp_sensor_registers *tsr;
455         u32 temp;
456         int ret;
457
458         ret = omap_bandgap_validate(bg_ptr, id);
459         if (ret)
460                 return ret;
461
462         if (!OMAP_BANDGAP_HAS(bg_ptr, TALERT))
463                 return -ENOTSUPP;
464
465         tsr = bg_ptr->conf->sensors[id].registers;
466         temp = omap_bandgap_readl(bg_ptr, tsr->bgap_threshold);
467         temp = (temp & tsr->threshold_thot_mask) >>
468                 __ffs(tsr->threshold_thot_mask);
469         ret |= omap_bandgap_adc_to_mcelsius(bg_ptr, temp, &temp);
470         if (ret) {
471                 dev_err(bg_ptr->dev, "failed to read thot\n");
472                 return -EIO;
473         }
474
475         *thot = temp;
476
477         return 0;
478 }
479
480 /**
481  * omap_bandgap_write_thot() - sets sensor current thot
482  * @bg_ptr - pointer to bandgap instance
483  * @id - sensor id
484  * @val - desired thot value
485  *
486  * returns 0 on success or the proper error code
487  */
488 int omap_bandgap_write_thot(struct omap_bandgap *bg_ptr, int id, int val)
489 {
490         struct temp_sensor_data *ts_data;
491         struct temp_sensor_registers *tsr;
492         u32 t_hot;
493         int ret;
494
495         ret = omap_bandgap_validate(bg_ptr, id);
496         if (ret)
497                 return ret;
498
499         if (!OMAP_BANDGAP_HAS(bg_ptr, TALERT))
500                 return -ENOTSUPP;
501
502         ts_data = bg_ptr->conf->sensors[id].ts_data;
503         tsr = bg_ptr->conf->sensors[id].registers;
504
505         if (val < ts_data->min_temp + ts_data->hyst_val)
506                 return -EINVAL;
507         ret = omap_bandgap_mcelsius_to_adc(bg_ptr, val, &t_hot);
508         if (ret < 0)
509                 return ret;
510
511         mutex_lock(&bg_ptr->bg_mutex);
512         temp_sensor_configure_thot(bg_ptr, id, t_hot);
513         mutex_unlock(&bg_ptr->bg_mutex);
514
515         return 0;
516 }
517
518 /**
519  * omap_bandgap_read_tcold() - reads sensor current tcold
520  * @bg_ptr - pointer to bandgap instance
521  * @id - sensor id
522  * @tcold - resulting current tcold value
523  *
524  * returns 0 on success or the proper error code
525  */
526 int omap_bandgap_read_tcold(struct omap_bandgap *bg_ptr, int id,
527                             int *tcold)
528 {
529         struct temp_sensor_registers *tsr;
530         u32 temp;
531         int ret;
532
533         ret = omap_bandgap_validate(bg_ptr, id);
534         if (ret)
535                 return ret;
536
537         if (!OMAP_BANDGAP_HAS(bg_ptr, TALERT))
538                 return -ENOTSUPP;
539
540         tsr = bg_ptr->conf->sensors[id].registers;
541         temp = omap_bandgap_readl(bg_ptr, tsr->bgap_threshold);
542         temp = (temp & tsr->threshold_tcold_mask)
543             >> __ffs(tsr->threshold_tcold_mask);
544         ret |= omap_bandgap_adc_to_mcelsius(bg_ptr, temp, &temp);
545         if (ret)
546                 return -EIO;
547
548         *tcold = temp;
549
550         return 0;
551 }
552
553 /**
554  * omap_bandgap_write_tcold() - sets the sensor tcold
555  * @bg_ptr - pointer to bandgap instance
556  * @id - sensor id
557  * @val - desired tcold value
558  *
559  * returns 0 on success or the proper error code
560  */
561 int omap_bandgap_write_tcold(struct omap_bandgap *bg_ptr, int id, int val)
562 {
563         struct temp_sensor_data *ts_data;
564         struct temp_sensor_registers *tsr;
565         u32 t_cold;
566         int ret;
567
568         ret = omap_bandgap_validate(bg_ptr, id);
569         if (ret)
570                 return ret;
571
572         if (!OMAP_BANDGAP_HAS(bg_ptr, TALERT))
573                 return -ENOTSUPP;
574
575         ts_data = bg_ptr->conf->sensors[id].ts_data;
576         tsr = bg_ptr->conf->sensors[id].registers;
577         if (val > ts_data->max_temp + ts_data->hyst_val)
578                 return -EINVAL;
579
580         ret = omap_bandgap_mcelsius_to_adc(bg_ptr, val, &t_cold);
581         if (ret < 0)
582                 return ret;
583
584         mutex_lock(&bg_ptr->bg_mutex);
585         temp_sensor_configure_tcold(bg_ptr, id, t_cold);
586         mutex_unlock(&bg_ptr->bg_mutex);
587
588         return 0;
589 }
590
591 /**
592  * omap_bandgap_read_update_interval() - read the sensor update interval
593  * @bg_ptr - pointer to bandgap instance
594  * @id - sensor id
595  * @interval - resulting update interval in miliseconds
596  *
597  * returns 0 on success or the proper error code
598  */
599 int omap_bandgap_read_update_interval(struct omap_bandgap *bg_ptr, int id,
600                                          int *interval)
601 {
602         struct temp_sensor_registers *tsr;
603         u32 time;
604         int ret;
605
606         ret = omap_bandgap_validate(bg_ptr, id);
607         if (ret)
608                 return ret;
609
610         if (!OMAP_BANDGAP_HAS(bg_ptr, COUNTER))
611                 return -ENOTSUPP;
612
613         tsr = bg_ptr->conf->sensors[id].registers;
614         time = omap_bandgap_readl(bg_ptr, tsr->bgap_counter);
615         time = (time & tsr->counter_mask) >> __ffs(tsr->counter_mask);
616         time = time * 1000 / bg_ptr->clk_rate;
617
618         *interval = time;
619
620         return 0;
621 }
622
623 /**
624  * omap_bandgap_write_update_interval() - set the update interval
625  * @bg_ptr - pointer to bandgap instance
626  * @id - sensor id
627  * @interval - desired update interval in miliseconds
628  *
629  * returns 0 on success or the proper error code
630  */
631 int omap_bandgap_write_update_interval(struct omap_bandgap *bg_ptr,
632                                        int id, u32 interval)
633 {
634         int ret = omap_bandgap_validate(bg_ptr, id);
635         if (ret)
636                 return ret;
637
638         if (!OMAP_BANDGAP_HAS(bg_ptr, COUNTER))
639                 return -ENOTSUPP;
640
641         interval = interval * bg_ptr->clk_rate / 1000;
642         mutex_lock(&bg_ptr->bg_mutex);
643         RMW_BITS(bg_ptr, id, bgap_counter, counter_mask, interval);
644         mutex_unlock(&bg_ptr->bg_mutex);
645
646         return 0;
647 }
648
649 /**
650  * omap_bandgap_read_temperature() - report current temperature
651  * @bg_ptr - pointer to bandgap instance
652  * @id - sensor id
653  * @temperature - resulting temperature
654  *
655  * returns 0 on success or the proper error code
656  */
657 int omap_bandgap_read_temperature(struct omap_bandgap *bg_ptr, int id,
658                                   int *temperature)
659 {
660         u32 temp;
661         int ret;
662
663         ret = omap_bandgap_validate(bg_ptr, id);
664         if (ret)
665                 return ret;
666
667         mutex_lock(&bg_ptr->bg_mutex);
668         temp = omap_bandgap_read_temp(bg_ptr, id);
669         mutex_unlock(&bg_ptr->bg_mutex);
670
671         ret |= omap_bandgap_adc_to_mcelsius(bg_ptr, temp, &temp);
672         if (ret)
673                 return -EIO;
674
675         *temperature = temp;
676
677         return 0;
678 }
679
680 /**
681  * omap_bandgap_set_sensor_data() - helper function to store thermal
682  * framework related data.
683  * @bg_ptr - pointer to bandgap instance
684  * @id - sensor id
685  * @data - thermal framework related data to be stored
686  *
687  * returns 0 on success or the proper error code
688  */
689 int omap_bandgap_set_sensor_data(struct omap_bandgap *bg_ptr, int id,
690                                  void *data)
691 {
692         int ret = omap_bandgap_validate(bg_ptr, id);
693         if (ret)
694                 return ret;
695
696         bg_ptr->conf->sensors[id].data = data;
697
698         return 0;
699 }
700
701 /**
702  * omap_bandgap_get_sensor_data() - helper function to get thermal
703  * framework related data.
704  * @bg_ptr - pointer to bandgap instance
705  * @id - sensor id
706  *
707  * returns data stored by set function with sensor id on success or NULL
708  */
709 void *omap_bandgap_get_sensor_data(struct omap_bandgap *bg_ptr, int id)
710 {
711         int ret = omap_bandgap_validate(bg_ptr, id);
712         if (ret)
713                 return ERR_PTR(ret);
714
715         return bg_ptr->conf->sensors[id].data;
716 }
717
718 static int
719 omap_bandgap_force_single_read(struct omap_bandgap *bg_ptr, int id)
720 {
721         u32 temp = 0, counter = 1000;
722
723         /* Select single conversion mode */
724         if (OMAP_BANDGAP_HAS(bg_ptr, MODE_CONFIG))
725                 RMW_BITS(bg_ptr, id, bgap_mode_ctrl, mode_ctrl_mask, 0);
726
727         /* Start of Conversion = 1 */
728         RMW_BITS(bg_ptr, id, temp_sensor_ctrl, bgap_soc_mask, 1);
729         /* Wait until DTEMP is updated */
730         temp = omap_bandgap_read_temp(bg_ptr, id);
731
732         while ((temp == 0) && --counter)
733                 temp = omap_bandgap_read_temp(bg_ptr, id);
734         /* REVISIT: Check correct condition for end of conversion */
735
736         /* Start of Conversion = 0 */
737         RMW_BITS(bg_ptr, id, temp_sensor_ctrl, bgap_soc_mask, 0);
738
739         return 0;
740 }
741
742 /**
743  * enable_continuous_mode() - One time enabling of continuous conversion mode
744  * @bg_ptr - pointer to scm instance
745  *
746  * Call this function only if HAS(MODE_CONFIG) is set
747  */
748 static int enable_continuous_mode(struct omap_bandgap *bg_ptr)
749 {
750         int i;
751
752         for (i = 0; i < bg_ptr->conf->sensor_count; i++) {
753                 /* Perform a single read just before enabling continuous */
754                 omap_bandgap_force_single_read(bg_ptr, i);
755                 RMW_BITS(bg_ptr, i, bgap_mode_ctrl, mode_ctrl_mask, 1);
756         }
757
758         return 0;
759 }
760
761 static int omap_bandgap_tshut_init(struct omap_bandgap *bg_ptr,
762                                    struct platform_device *pdev)
763 {
764         int gpio_nr = bg_ptr->tshut_gpio;
765         int status;
766
767         /* Request for gpio_86 line */
768         status = gpio_request(gpio_nr, "tshut");
769         if (status < 0) {
770                 dev_err(bg_ptr->dev,
771                         "Could not request for TSHUT GPIO:%i\n", 86);
772                 return status;
773         }
774         status = gpio_direction_input(gpio_nr);
775         if (status) {
776                 dev_err(bg_ptr->dev,
777                         "Cannot set input TSHUT GPIO %d\n", gpio_nr);
778                 return status;
779         }
780
781         status = request_irq(gpio_to_irq(gpio_nr),
782                              omap_bandgap_tshut_irq_handler,
783                              IRQF_TRIGGER_RISING, "tshut",
784                              NULL);
785         if (status) {
786                 gpio_free(gpio_nr);
787                 dev_err(bg_ptr->dev, "request irq failed for TSHUT");
788         }
789
790         return 0;
791 }
792
793 /* Initialization of Talert. Call it only if HAS(TALERT) is set */
794 static int omap_bandgap_talert_init(struct omap_bandgap *bg_ptr,
795                                     struct platform_device *pdev)
796 {
797         int ret;
798
799         bg_ptr->irq = platform_get_irq(pdev, 0);
800         if (bg_ptr->irq < 0) {
801                 dev_err(&pdev->dev, "get_irq failed\n");
802                 return bg_ptr->irq;
803         }
804         ret = request_threaded_irq(bg_ptr->irq, NULL,
805                                    omap_bandgap_talert_irq_handler,
806                                    IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
807                                    "talert", bg_ptr);
808         if (ret) {
809                 dev_err(&pdev->dev, "Request threaded irq failed.\n");
810                 return ret;
811         }
812
813         return 0;
814 }
815
816 static const struct of_device_id of_omap_bandgap_match[];
817 static struct omap_bandgap *omap_bandgap_build(struct platform_device *pdev)
818 {
819         struct device_node *node = pdev->dev.of_node;
820         const struct of_device_id *of_id;
821         struct omap_bandgap *bg_ptr;
822         struct resource *res;
823         u32 prop;
824         int i;
825
826         /* just for the sake */
827         if (!node) {
828                 dev_err(&pdev->dev, "no platform information available\n");
829                 return ERR_PTR(-EINVAL);
830         }
831
832         bg_ptr = devm_kzalloc(&pdev->dev, sizeof(struct omap_bandgap),
833                                     GFP_KERNEL);
834         if (!bg_ptr) {
835                 dev_err(&pdev->dev, "Unable to allocate mem for driver ref\n");
836                 return ERR_PTR(-ENOMEM);
837         }
838
839         of_id = of_match_device(of_omap_bandgap_match, &pdev->dev);
840         if (of_id)
841                 bg_ptr->conf = of_id->data;
842
843         i = 0;
844         do {
845                 void __iomem *chunk;
846
847                 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
848                 if (!res)
849                         break;
850                 chunk = devm_ioremap_resource(&pdev->dev, res);
851                 if (i == 0)
852                         bg_ptr->base = chunk;
853                 if (IS_ERR(chunk))
854                         return ERR_CAST(chunk);
855
856                 i++;
857         } while (res);
858
859         if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT)) {
860                 if (of_property_read_u32(node, "ti,tshut-gpio", &prop) < 0) {
861                         dev_err(&pdev->dev, "missing tshut gpio in device tree\n");
862                         return ERR_PTR(-EINVAL);
863                 }
864                 bg_ptr->tshut_gpio = prop;
865                 if (!gpio_is_valid(bg_ptr->tshut_gpio)) {
866                         dev_err(&pdev->dev, "invalid gpio for tshut (%d)\n",
867                                 bg_ptr->tshut_gpio);
868                         return ERR_PTR(-EINVAL);
869                 }
870         }
871
872         return bg_ptr;
873 }
874
875 static
876 int omap_bandgap_probe(struct platform_device *pdev)
877 {
878         struct omap_bandgap *bg_ptr;
879         int clk_rate, ret = 0, i;
880
881         bg_ptr = omap_bandgap_build(pdev);
882         if (IS_ERR_OR_NULL(bg_ptr)) {
883                 dev_err(&pdev->dev, "failed to fetch platform data\n");
884                 return PTR_ERR(bg_ptr);
885         }
886         bg_ptr->dev = &pdev->dev;
887
888         if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT)) {
889                 ret = omap_bandgap_tshut_init(bg_ptr, pdev);
890                 if (ret) {
891                         dev_err(&pdev->dev,
892                                 "failed to initialize system tshut IRQ\n");
893                         return ret;
894                 }
895         }
896
897         bg_ptr->fclock = clk_get(NULL, bg_ptr->conf->fclock_name);
898         ret = IS_ERR_OR_NULL(bg_ptr->fclock);
899         if (ret) {
900                 dev_err(&pdev->dev, "failed to request fclock reference\n");
901                 goto free_irqs;
902         }
903
904         bg_ptr->div_clk = clk_get(NULL,  bg_ptr->conf->div_ck_name);
905         ret = IS_ERR_OR_NULL(bg_ptr->div_clk);
906         if (ret) {
907                 dev_err(&pdev->dev,
908                         "failed to request div_ts_ck clock ref\n");
909                 goto free_irqs;
910         }
911
912         for (i = 0; i < bg_ptr->conf->sensor_count; i++) {
913                 struct temp_sensor_registers *tsr;
914                 u32 val;
915
916                 tsr = bg_ptr->conf->sensors[i].registers;
917                 /*
918                  * check if the efuse has a non-zero value if not
919                  * it is an untrimmed sample and the temperatures
920                  * may not be accurate
921                  */
922                 val = omap_bandgap_readl(bg_ptr, tsr->bgap_efuse);
923                 if (ret || !val)
924                         dev_info(&pdev->dev,
925                                  "Non-trimmed BGAP, Temp not accurate\n");
926         }
927
928         clk_rate = clk_round_rate(bg_ptr->div_clk,
929                                   bg_ptr->conf->sensors[0].ts_data->max_freq);
930         if (clk_rate < bg_ptr->conf->sensors[0].ts_data->min_freq ||
931             clk_rate == 0xffffffff) {
932                 ret = -ENODEV;
933                 dev_err(&pdev->dev, "wrong clock rate (%d)\n", clk_rate);
934                 goto put_clks;
935         }
936
937         ret = clk_set_rate(bg_ptr->div_clk, clk_rate);
938         if (ret)
939                 dev_err(&pdev->dev, "Cannot re-set clock rate. Continuing\n");
940
941         bg_ptr->clk_rate = clk_rate;
942         if (OMAP_BANDGAP_HAS(bg_ptr, CLK_CTRL))
943                 clk_prepare_enable(bg_ptr->fclock);
944
945
946         mutex_init(&bg_ptr->bg_mutex);
947         bg_ptr->dev = &pdev->dev;
948         platform_set_drvdata(pdev, bg_ptr);
949
950         omap_bandgap_power(bg_ptr, true);
951
952         /* Set default counter to 1 for now */
953         if (OMAP_BANDGAP_HAS(bg_ptr, COUNTER))
954                 for (i = 0; i < bg_ptr->conf->sensor_count; i++)
955                         RMW_BITS(bg_ptr, i, bgap_counter, counter_mask, 1);
956
957         /* Set default thresholds for alert and shutdown */
958         for (i = 0; i < bg_ptr->conf->sensor_count; i++) {
959                 struct temp_sensor_data *ts_data;
960
961                 ts_data = bg_ptr->conf->sensors[i].ts_data;
962
963                 if (OMAP_BANDGAP_HAS(bg_ptr, TALERT)) {
964                         /* Set initial Talert thresholds */
965                         RMW_BITS(bg_ptr, i, bgap_threshold,
966                                  threshold_tcold_mask, ts_data->t_cold);
967                         RMW_BITS(bg_ptr, i, bgap_threshold,
968                                  threshold_thot_mask, ts_data->t_hot);
969                         /* Enable the alert events */
970                         RMW_BITS(bg_ptr, i, bgap_mask_ctrl, mask_hot_mask, 1);
971                         RMW_BITS(bg_ptr, i, bgap_mask_ctrl, mask_cold_mask, 1);
972                 }
973
974                 if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT_CONFIG)) {
975                         /* Set initial Tshut thresholds */
976                         RMW_BITS(bg_ptr, i, tshut_threshold,
977                                  tshut_hot_mask, ts_data->tshut_hot);
978                         RMW_BITS(bg_ptr, i, tshut_threshold,
979                                  tshut_cold_mask, ts_data->tshut_cold);
980                 }
981         }
982
983         if (OMAP_BANDGAP_HAS(bg_ptr, MODE_CONFIG))
984                 enable_continuous_mode(bg_ptr);
985
986         /* Set .250 seconds time as default counter */
987         if (OMAP_BANDGAP_HAS(bg_ptr, COUNTER))
988                 for (i = 0; i < bg_ptr->conf->sensor_count; i++)
989                         RMW_BITS(bg_ptr, i, bgap_counter, counter_mask,
990                                  bg_ptr->clk_rate / 4);
991
992         /* Every thing is good? Then expose the sensors */
993         for (i = 0; i < bg_ptr->conf->sensor_count; i++) {
994                 char *domain;
995
996                 if (bg_ptr->conf->sensors[i].register_cooling)
997                         bg_ptr->conf->sensors[i].register_cooling(bg_ptr, i);
998
999                 domain = bg_ptr->conf->sensors[i].domain;
1000                 if (bg_ptr->conf->expose_sensor)
1001                         bg_ptr->conf->expose_sensor(bg_ptr, i, domain);
1002         }
1003
1004         /*
1005          * Enable the Interrupts once everything is set. Otherwise irq handler
1006          * might be called as soon as it is enabled where as rest of framework
1007          * is still getting initialised.
1008          */
1009         if (OMAP_BANDGAP_HAS(bg_ptr, TALERT)) {
1010                 ret = omap_bandgap_talert_init(bg_ptr, pdev);
1011                 if (ret) {
1012                         dev_err(&pdev->dev, "failed to initialize Talert IRQ\n");
1013                         i = bg_ptr->conf->sensor_count;
1014                         goto disable_clk;
1015                 }
1016         }
1017
1018         return 0;
1019
1020 disable_clk:
1021         if (OMAP_BANDGAP_HAS(bg_ptr, CLK_CTRL))
1022                 clk_disable_unprepare(bg_ptr->fclock);
1023 put_clks:
1024         clk_put(bg_ptr->fclock);
1025         clk_put(bg_ptr->div_clk);
1026 free_irqs:
1027         if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT)) {
1028                 free_irq(gpio_to_irq(bg_ptr->tshut_gpio), NULL);
1029                 gpio_free(bg_ptr->tshut_gpio);
1030         }
1031
1032         return ret;
1033 }
1034
1035 static
1036 int omap_bandgap_remove(struct platform_device *pdev)
1037 {
1038         struct omap_bandgap *bg_ptr = platform_get_drvdata(pdev);
1039         int i;
1040
1041         /* First thing is to remove sensor interfaces */
1042         for (i = 0; i < bg_ptr->conf->sensor_count; i++) {
1043                 if (bg_ptr->conf->sensors[i].register_cooling)
1044                         bg_ptr->conf->sensors[i].unregister_cooling(bg_ptr, i);
1045
1046                 if (bg_ptr->conf->remove_sensor)
1047                         bg_ptr->conf->remove_sensor(bg_ptr, i);
1048         }
1049
1050         omap_bandgap_power(bg_ptr, false);
1051
1052         if (OMAP_BANDGAP_HAS(bg_ptr, CLK_CTRL))
1053                 clk_disable_unprepare(bg_ptr->fclock);
1054         clk_put(bg_ptr->fclock);
1055         clk_put(bg_ptr->div_clk);
1056
1057         if (OMAP_BANDGAP_HAS(bg_ptr, TALERT))
1058                 free_irq(bg_ptr->irq, bg_ptr);
1059
1060         if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT)) {
1061                 free_irq(gpio_to_irq(bg_ptr->tshut_gpio), NULL);
1062                 gpio_free(bg_ptr->tshut_gpio);
1063         }
1064
1065         return 0;
1066 }
1067
1068 #ifdef CONFIG_PM
1069 static int omap_bandgap_save_ctxt(struct omap_bandgap *bg_ptr)
1070 {
1071         int i;
1072
1073         for (i = 0; i < bg_ptr->conf->sensor_count; i++) {
1074                 struct temp_sensor_registers *tsr;
1075                 struct temp_sensor_regval *rval;
1076
1077                 rval = &bg_ptr->conf->sensors[i].regval;
1078                 tsr = bg_ptr->conf->sensors[i].registers;
1079
1080                 if (OMAP_BANDGAP_HAS(bg_ptr, MODE_CONFIG))
1081                         rval->bg_mode_ctrl = omap_bandgap_readl(bg_ptr,
1082                                                         tsr->bgap_mode_ctrl);
1083                 if (OMAP_BANDGAP_HAS(bg_ptr, COUNTER))
1084                         rval->bg_counter = omap_bandgap_readl(bg_ptr,
1085                                                         tsr->bgap_counter);
1086                 if (OMAP_BANDGAP_HAS(bg_ptr, TALERT)) {
1087                         rval->bg_threshold = omap_bandgap_readl(bg_ptr,
1088                                                         tsr->bgap_threshold);
1089                         rval->bg_ctrl = omap_bandgap_readl(bg_ptr,
1090                                                    tsr->bgap_mask_ctrl);
1091                 }
1092
1093                 if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT_CONFIG))
1094                         rval->tshut_threshold = omap_bandgap_readl(bg_ptr,
1095                                                    tsr->tshut_threshold);
1096         }
1097
1098         return 0;
1099 }
1100
1101 static int omap_bandgap_restore_ctxt(struct omap_bandgap *bg_ptr)
1102 {
1103         int i;
1104
1105         for (i = 0; i < bg_ptr->conf->sensor_count; i++) {
1106                 struct temp_sensor_registers *tsr;
1107                 struct temp_sensor_regval *rval;
1108                 u32 val = 0;
1109
1110                 rval = &bg_ptr->conf->sensors[i].regval;
1111                 tsr = bg_ptr->conf->sensors[i].registers;
1112
1113                 if (OMAP_BANDGAP_HAS(bg_ptr, COUNTER))
1114                         val = omap_bandgap_readl(bg_ptr, tsr->bgap_counter);
1115
1116                 if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT_CONFIG))
1117                         omap_bandgap_writel(bg_ptr, rval->tshut_threshold,
1118                                             tsr->tshut_threshold);
1119                 /* Force immediate temperature measurement and update
1120                  * of the DTEMP field
1121                  */
1122                 omap_bandgap_force_single_read(bg_ptr, i);
1123
1124                 if (OMAP_BANDGAP_HAS(bg_ptr, COUNTER))
1125                         omap_bandgap_writel(bg_ptr, rval->bg_counter,
1126                                             tsr->bgap_counter);
1127                 if (OMAP_BANDGAP_HAS(bg_ptr, MODE_CONFIG))
1128                         omap_bandgap_writel(bg_ptr, rval->bg_mode_ctrl,
1129                                             tsr->bgap_mode_ctrl);
1130                 if (OMAP_BANDGAP_HAS(bg_ptr, TALERT)) {
1131                         omap_bandgap_writel(bg_ptr, rval->bg_threshold,
1132                                             tsr->bgap_threshold);
1133                         omap_bandgap_writel(bg_ptr, rval->bg_ctrl,
1134                                             tsr->bgap_mask_ctrl);
1135                 }
1136         }
1137
1138         return 0;
1139 }
1140
1141 static int omap_bandgap_suspend(struct device *dev)
1142 {
1143         struct omap_bandgap *bg_ptr = dev_get_drvdata(dev);
1144         int err;
1145
1146         err = omap_bandgap_save_ctxt(bg_ptr);
1147         omap_bandgap_power(bg_ptr, false);
1148
1149         if (OMAP_BANDGAP_HAS(bg_ptr, CLK_CTRL))
1150                 clk_disable_unprepare(bg_ptr->fclock);
1151
1152         return err;
1153 }
1154
1155 static int omap_bandgap_resume(struct device *dev)
1156 {
1157         struct omap_bandgap *bg_ptr = dev_get_drvdata(dev);
1158
1159         if (OMAP_BANDGAP_HAS(bg_ptr, CLK_CTRL))
1160                 clk_prepare_enable(bg_ptr->fclock);
1161
1162         omap_bandgap_power(bg_ptr, true);
1163
1164         return omap_bandgap_restore_ctxt(bg_ptr);
1165 }
1166 static const struct dev_pm_ops omap_bandgap_dev_pm_ops = {
1167         SET_SYSTEM_SLEEP_PM_OPS(omap_bandgap_suspend,
1168                                 omap_bandgap_resume)
1169 };
1170
1171 #define DEV_PM_OPS      (&omap_bandgap_dev_pm_ops)
1172 #else
1173 #define DEV_PM_OPS      NULL
1174 #endif
1175
1176 static const struct of_device_id of_omap_bandgap_match[] = {
1177 #ifdef CONFIG_OMAP4_THERMAL
1178         {
1179                 .compatible = "ti,omap4430-bandgap",
1180                 .data = (void *)&omap4430_data,
1181         },
1182         {
1183                 .compatible = "ti,omap4460-bandgap",
1184                 .data = (void *)&omap4460_data,
1185         },
1186         {
1187                 .compatible = "ti,omap4470-bandgap",
1188                 .data = (void *)&omap4470_data,
1189         },
1190 #endif
1191 #ifdef CONFIG_OMAP5_THERMAL
1192         {
1193                 .compatible = "ti,omap5430-bandgap",
1194                 .data = (void *)&omap5430_data,
1195         },
1196 #endif
1197         /* Sentinel */
1198         { },
1199 };
1200 MODULE_DEVICE_TABLE(of, of_omap_bandgap_match);
1201
1202 static struct platform_driver omap_bandgap_sensor_driver = {
1203         .probe = omap_bandgap_probe,
1204         .remove = omap_bandgap_remove,
1205         .driver = {
1206                         .name = "omap-bandgap",
1207                         .pm = DEV_PM_OPS,
1208                         .of_match_table = of_omap_bandgap_match,
1209         },
1210 };
1211
1212 module_platform_driver(omap_bandgap_sensor_driver);
1213
1214 MODULE_DESCRIPTION("OMAP4+ bandgap temperature sensor driver");
1215 MODULE_LICENSE("GPL v2");
1216 MODULE_ALIAS("platform:omap-bandgap");
1217 MODULE_AUTHOR("Texas Instrument Inc.");