staging: omap-thermal: threshold manipulation section
[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 /**
307  * omap_bandgap_add_hyst() - add hysteresis (in mCelsius) to an ADC value
308  * @bg_ptr: struct omap_bandgap pointer
309  * @adc_val: temperature value in ADC representation
310  * @hyst_val: hysteresis value in mCelsius
311  * @sum: address where to write the resulting temperature (in ADC scale)
312  *
313  * Adds an hysteresis value (in mCelsius) to a ADC temperature value.
314  * Returns 0 on success, -ERANGE otherwise.
315  */
316 static
317 int omap_bandgap_add_hyst(struct omap_bandgap *bg_ptr, int adc_val,
318                           int hyst_val, u32 *sum)
319 {
320         int temp, ret;
321
322         /*
323          * Need to add in the mcelsius domain, so we have a temperature
324          * the conv_table range
325          */
326         ret = omap_bandgap_adc_to_mcelsius(bg_ptr, adc_val, &temp);
327         if (ret < 0)
328                 goto exit;
329
330         temp += hyst_val;
331
332         ret = omap_bandgap_mcelsius_to_adc(bg_ptr, temp, sum);
333
334 exit:
335         return ret;
336 }
337
338 /***   Helper functions handling device Alert/Shutdown signals   ***/
339
340 /* Talert masks. Call it only if HAS(TALERT) is set */
341 static int temp_sensor_unmask_interrupts(struct omap_bandgap *bg_ptr, int id,
342                                          u32 t_hot, u32 t_cold)
343 {
344         struct temp_sensor_registers *tsr;
345         u32 temp, reg_val;
346
347         /* Read the current on die temperature */
348         temp = omap_bandgap_read_temp(bg_ptr, id);
349
350         tsr = bg_ptr->conf->sensors[id].registers;
351         reg_val = omap_bandgap_readl(bg_ptr, tsr->bgap_mask_ctrl);
352
353         if (temp < t_hot)
354                 reg_val |= tsr->mask_hot_mask;
355         else
356                 reg_val &= ~tsr->mask_hot_mask;
357
358         if (t_cold < temp)
359                 reg_val |= tsr->mask_cold_mask;
360         else
361                 reg_val &= ~tsr->mask_cold_mask;
362         omap_bandgap_writel(bg_ptr, reg_val, tsr->bgap_mask_ctrl);
363
364         return 0;
365 }
366
367 /* Talert Thot threshold. Call it only if HAS(TALERT) is set */
368 static
369 int temp_sensor_configure_thot(struct omap_bandgap *bg_ptr, int id, int t_hot)
370 {
371         struct temp_sensor_data *ts_data = bg_ptr->conf->sensors[id].ts_data;
372         struct temp_sensor_registers *tsr;
373         u32 thresh_val, reg_val;
374         int cold, err = 0;
375
376         tsr = bg_ptr->conf->sensors[id].registers;
377
378         /* obtain the T cold value */
379         thresh_val = omap_bandgap_readl(bg_ptr, tsr->bgap_threshold);
380         cold = (thresh_val & tsr->threshold_tcold_mask) >>
381             __ffs(tsr->threshold_tcold_mask);
382         if (t_hot <= cold) {
383                 /* change the t_cold to t_hot - 5000 millidegrees */
384                 err |= omap_bandgap_add_hyst(bg_ptr, t_hot,
385                                              -ts_data->hyst_val, &cold);
386                 /* write the new t_cold value */
387                 reg_val = thresh_val & (~tsr->threshold_tcold_mask);
388                 reg_val |= cold << __ffs(tsr->threshold_tcold_mask);
389                 omap_bandgap_writel(bg_ptr, reg_val, tsr->bgap_threshold);
390                 thresh_val = reg_val;
391         }
392
393         /* write the new t_hot value */
394         reg_val = thresh_val & ~tsr->threshold_thot_mask;
395         reg_val |= (t_hot << __ffs(tsr->threshold_thot_mask));
396         omap_bandgap_writel(bg_ptr, reg_val, tsr->bgap_threshold);
397         if (err) {
398                 dev_err(bg_ptr->dev, "failed to reprogram thot threshold\n");
399                 return -EIO;
400         }
401
402         return temp_sensor_unmask_interrupts(bg_ptr, id, t_hot, cold);
403 }
404
405 /* Talert Tcold threshold. Call it only if HAS(TALERT) is set */
406 static
407 int temp_sensor_configure_tcold(struct omap_bandgap *bg_ptr, int id,
408                                 int t_cold)
409 {
410         struct temp_sensor_data *ts_data = bg_ptr->conf->sensors[id].ts_data;
411         struct temp_sensor_registers *tsr;
412         u32 thresh_val, reg_val;
413         int hot, err = 0;
414
415         tsr = bg_ptr->conf->sensors[id].registers;
416         /* obtain the T cold value */
417         thresh_val = omap_bandgap_readl(bg_ptr, tsr->bgap_threshold);
418         hot = (thresh_val & tsr->threshold_thot_mask) >>
419             __ffs(tsr->threshold_thot_mask);
420
421         if (t_cold >= hot) {
422                 /* change the t_hot to t_cold + 5000 millidegrees */
423                 err |= omap_bandgap_add_hyst(bg_ptr, t_cold,
424                                              ts_data->hyst_val, &hot);
425                 /* write the new t_hot value */
426                 reg_val = thresh_val & (~tsr->threshold_thot_mask);
427                 reg_val |= hot << __ffs(tsr->threshold_thot_mask);
428                 omap_bandgap_writel(bg_ptr, reg_val, tsr->bgap_threshold);
429                 thresh_val = reg_val;
430         }
431
432         /* write the new t_cold value */
433         reg_val = thresh_val & ~tsr->threshold_tcold_mask;
434         reg_val |= (t_cold << __ffs(tsr->threshold_tcold_mask));
435         omap_bandgap_writel(bg_ptr, reg_val, tsr->bgap_threshold);
436         if (err) {
437                 dev_err(bg_ptr->dev, "failed to reprogram tcold threshold\n");
438                 return -EIO;
439         }
440
441         return temp_sensor_unmask_interrupts(bg_ptr, id, hot, t_cold);
442 }
443
444 #define bandgap_is_valid(b)                                             \
445                         (!IS_ERR_OR_NULL(b))
446 #define bandgap_is_valid_sensor_id(b, i)                                \
447                         ((i) >= 0 && (i) < (b)->conf->sensor_count)
448 static inline int omap_bandgap_validate(struct omap_bandgap *bg_ptr, int id)
449 {
450         if (!bandgap_is_valid(bg_ptr)) {
451                 pr_err("%s: invalid bandgap pointer\n", __func__);
452                 return -EINVAL;
453         }
454
455         if (!bandgap_is_valid_sensor_id(bg_ptr, id)) {
456                 dev_err(bg_ptr->dev, "%s: sensor id out of range (%d)\n",
457                         __func__, id);
458                 return -ERANGE;
459         }
460
461         return 0;
462 }
463
464 /* Exposed APIs */
465 /**
466  * omap_bandgap_read_thot() - reads sensor current thot
467  * @bg_ptr - pointer to bandgap instance
468  * @id - sensor id
469  * @thot - resulting current thot value
470  *
471  * returns 0 on success or the proper error code
472  */
473 int omap_bandgap_read_thot(struct omap_bandgap *bg_ptr, int id,
474                            int *thot)
475 {
476         struct temp_sensor_registers *tsr;
477         u32 temp;
478         int ret;
479
480         ret = omap_bandgap_validate(bg_ptr, id);
481         if (ret)
482                 return ret;
483
484         if (!OMAP_BANDGAP_HAS(bg_ptr, TALERT))
485                 return -ENOTSUPP;
486
487         tsr = bg_ptr->conf->sensors[id].registers;
488         temp = omap_bandgap_readl(bg_ptr, tsr->bgap_threshold);
489         temp = (temp & tsr->threshold_thot_mask) >>
490                 __ffs(tsr->threshold_thot_mask);
491         ret |= omap_bandgap_adc_to_mcelsius(bg_ptr, temp, &temp);
492         if (ret) {
493                 dev_err(bg_ptr->dev, "failed to read thot\n");
494                 return -EIO;
495         }
496
497         *thot = temp;
498
499         return 0;
500 }
501
502 /**
503  * omap_bandgap_write_thot() - sets sensor current thot
504  * @bg_ptr - pointer to bandgap instance
505  * @id - sensor id
506  * @val - desired thot value
507  *
508  * returns 0 on success or the proper error code
509  */
510 int omap_bandgap_write_thot(struct omap_bandgap *bg_ptr, int id, int val)
511 {
512         struct temp_sensor_data *ts_data;
513         struct temp_sensor_registers *tsr;
514         u32 t_hot;
515         int ret;
516
517         ret = omap_bandgap_validate(bg_ptr, id);
518         if (ret)
519                 return ret;
520
521         if (!OMAP_BANDGAP_HAS(bg_ptr, TALERT))
522                 return -ENOTSUPP;
523
524         ts_data = bg_ptr->conf->sensors[id].ts_data;
525         tsr = bg_ptr->conf->sensors[id].registers;
526
527         if (val < ts_data->min_temp + ts_data->hyst_val)
528                 return -EINVAL;
529         ret = omap_bandgap_mcelsius_to_adc(bg_ptr, val, &t_hot);
530         if (ret < 0)
531                 return ret;
532
533         mutex_lock(&bg_ptr->bg_mutex);
534         temp_sensor_configure_thot(bg_ptr, id, t_hot);
535         mutex_unlock(&bg_ptr->bg_mutex);
536
537         return 0;
538 }
539
540 /**
541  * omap_bandgap_read_tcold() - reads sensor current tcold
542  * @bg_ptr - pointer to bandgap instance
543  * @id - sensor id
544  * @tcold - resulting current tcold value
545  *
546  * returns 0 on success or the proper error code
547  */
548 int omap_bandgap_read_tcold(struct omap_bandgap *bg_ptr, int id,
549                             int *tcold)
550 {
551         struct temp_sensor_registers *tsr;
552         u32 temp;
553         int ret;
554
555         ret = omap_bandgap_validate(bg_ptr, id);
556         if (ret)
557                 return ret;
558
559         if (!OMAP_BANDGAP_HAS(bg_ptr, TALERT))
560                 return -ENOTSUPP;
561
562         tsr = bg_ptr->conf->sensors[id].registers;
563         temp = omap_bandgap_readl(bg_ptr, tsr->bgap_threshold);
564         temp = (temp & tsr->threshold_tcold_mask)
565             >> __ffs(tsr->threshold_tcold_mask);
566         ret |= omap_bandgap_adc_to_mcelsius(bg_ptr, temp, &temp);
567         if (ret)
568                 return -EIO;
569
570         *tcold = temp;
571
572         return 0;
573 }
574
575 /**
576  * omap_bandgap_write_tcold() - sets the sensor tcold
577  * @bg_ptr - pointer to bandgap instance
578  * @id - sensor id
579  * @val - desired tcold value
580  *
581  * returns 0 on success or the proper error code
582  */
583 int omap_bandgap_write_tcold(struct omap_bandgap *bg_ptr, int id, int val)
584 {
585         struct temp_sensor_data *ts_data;
586         struct temp_sensor_registers *tsr;
587         u32 t_cold;
588         int ret;
589
590         ret = omap_bandgap_validate(bg_ptr, id);
591         if (ret)
592                 return ret;
593
594         if (!OMAP_BANDGAP_HAS(bg_ptr, TALERT))
595                 return -ENOTSUPP;
596
597         ts_data = bg_ptr->conf->sensors[id].ts_data;
598         tsr = bg_ptr->conf->sensors[id].registers;
599         if (val > ts_data->max_temp + ts_data->hyst_val)
600                 return -EINVAL;
601
602         ret = omap_bandgap_mcelsius_to_adc(bg_ptr, val, &t_cold);
603         if (ret < 0)
604                 return ret;
605
606         mutex_lock(&bg_ptr->bg_mutex);
607         temp_sensor_configure_tcold(bg_ptr, id, t_cold);
608         mutex_unlock(&bg_ptr->bg_mutex);
609
610         return 0;
611 }
612
613 /**
614  * omap_bandgap_read_update_interval() - read the sensor update interval
615  * @bg_ptr - pointer to bandgap instance
616  * @id - sensor id
617  * @interval - resulting update interval in miliseconds
618  *
619  * returns 0 on success or the proper error code
620  */
621 int omap_bandgap_read_update_interval(struct omap_bandgap *bg_ptr, int id,
622                                          int *interval)
623 {
624         struct temp_sensor_registers *tsr;
625         u32 time;
626         int ret;
627
628         ret = omap_bandgap_validate(bg_ptr, id);
629         if (ret)
630                 return ret;
631
632         if (!OMAP_BANDGAP_HAS(bg_ptr, COUNTER))
633                 return -ENOTSUPP;
634
635         tsr = bg_ptr->conf->sensors[id].registers;
636         time = omap_bandgap_readl(bg_ptr, tsr->bgap_counter);
637         time = (time & tsr->counter_mask) >> __ffs(tsr->counter_mask);
638         time = time * 1000 / bg_ptr->clk_rate;
639
640         *interval = time;
641
642         return 0;
643 }
644
645 /**
646  * omap_bandgap_write_update_interval() - set the update interval
647  * @bg_ptr - pointer to bandgap instance
648  * @id - sensor id
649  * @interval - desired update interval in miliseconds
650  *
651  * returns 0 on success or the proper error code
652  */
653 int omap_bandgap_write_update_interval(struct omap_bandgap *bg_ptr,
654                                        int id, u32 interval)
655 {
656         int ret = omap_bandgap_validate(bg_ptr, id);
657         if (ret)
658                 return ret;
659
660         if (!OMAP_BANDGAP_HAS(bg_ptr, COUNTER))
661                 return -ENOTSUPP;
662
663         interval = interval * bg_ptr->clk_rate / 1000;
664         mutex_lock(&bg_ptr->bg_mutex);
665         RMW_BITS(bg_ptr, id, bgap_counter, counter_mask, interval);
666         mutex_unlock(&bg_ptr->bg_mutex);
667
668         return 0;
669 }
670
671 /**
672  * omap_bandgap_read_temperature() - report current temperature
673  * @bg_ptr - pointer to bandgap instance
674  * @id - sensor id
675  * @temperature - resulting temperature
676  *
677  * returns 0 on success or the proper error code
678  */
679 int omap_bandgap_read_temperature(struct omap_bandgap *bg_ptr, int id,
680                                   int *temperature)
681 {
682         u32 temp;
683         int ret;
684
685         ret = omap_bandgap_validate(bg_ptr, id);
686         if (ret)
687                 return ret;
688
689         mutex_lock(&bg_ptr->bg_mutex);
690         temp = omap_bandgap_read_temp(bg_ptr, id);
691         mutex_unlock(&bg_ptr->bg_mutex);
692
693         ret |= omap_bandgap_adc_to_mcelsius(bg_ptr, temp, &temp);
694         if (ret)
695                 return -EIO;
696
697         *temperature = temp;
698
699         return 0;
700 }
701
702 /**
703  * omap_bandgap_set_sensor_data() - helper function to store thermal
704  * framework related data.
705  * @bg_ptr - pointer to bandgap instance
706  * @id - sensor id
707  * @data - thermal framework related data to be stored
708  *
709  * returns 0 on success or the proper error code
710  */
711 int omap_bandgap_set_sensor_data(struct omap_bandgap *bg_ptr, int id,
712                                  void *data)
713 {
714         int ret = omap_bandgap_validate(bg_ptr, id);
715         if (ret)
716                 return ret;
717
718         bg_ptr->conf->sensors[id].data = data;
719
720         return 0;
721 }
722
723 /**
724  * omap_bandgap_get_sensor_data() - helper function to get thermal
725  * framework related data.
726  * @bg_ptr - pointer to bandgap instance
727  * @id - sensor id
728  *
729  * returns data stored by set function with sensor id on success or NULL
730  */
731 void *omap_bandgap_get_sensor_data(struct omap_bandgap *bg_ptr, int id)
732 {
733         int ret = omap_bandgap_validate(bg_ptr, id);
734         if (ret)
735                 return ERR_PTR(ret);
736
737         return bg_ptr->conf->sensors[id].data;
738 }
739
740 static int
741 omap_bandgap_force_single_read(struct omap_bandgap *bg_ptr, int id)
742 {
743         u32 temp = 0, counter = 1000;
744
745         /* Select single conversion mode */
746         if (OMAP_BANDGAP_HAS(bg_ptr, MODE_CONFIG))
747                 RMW_BITS(bg_ptr, id, bgap_mode_ctrl, mode_ctrl_mask, 0);
748
749         /* Start of Conversion = 1 */
750         RMW_BITS(bg_ptr, id, temp_sensor_ctrl, bgap_soc_mask, 1);
751         /* Wait until DTEMP is updated */
752         temp = omap_bandgap_read_temp(bg_ptr, id);
753
754         while ((temp == 0) && --counter)
755                 temp = omap_bandgap_read_temp(bg_ptr, id);
756         /* REVISIT: Check correct condition for end of conversion */
757
758         /* Start of Conversion = 0 */
759         RMW_BITS(bg_ptr, id, temp_sensor_ctrl, bgap_soc_mask, 0);
760
761         return 0;
762 }
763
764 /**
765  * enable_continuous_mode() - One time enabling of continuous conversion mode
766  * @bg_ptr - pointer to scm instance
767  *
768  * Call this function only if HAS(MODE_CONFIG) is set
769  */
770 static int enable_continuous_mode(struct omap_bandgap *bg_ptr)
771 {
772         int i;
773
774         for (i = 0; i < bg_ptr->conf->sensor_count; i++) {
775                 /* Perform a single read just before enabling continuous */
776                 omap_bandgap_force_single_read(bg_ptr, i);
777                 RMW_BITS(bg_ptr, i, bgap_mode_ctrl, mode_ctrl_mask, 1);
778         }
779
780         return 0;
781 }
782
783 static int omap_bandgap_tshut_init(struct omap_bandgap *bg_ptr,
784                                    struct platform_device *pdev)
785 {
786         int gpio_nr = bg_ptr->tshut_gpio;
787         int status;
788
789         /* Request for gpio_86 line */
790         status = gpio_request(gpio_nr, "tshut");
791         if (status < 0) {
792                 dev_err(bg_ptr->dev,
793                         "Could not request for TSHUT GPIO:%i\n", 86);
794                 return status;
795         }
796         status = gpio_direction_input(gpio_nr);
797         if (status) {
798                 dev_err(bg_ptr->dev,
799                         "Cannot set input TSHUT GPIO %d\n", gpio_nr);
800                 return status;
801         }
802
803         status = request_irq(gpio_to_irq(gpio_nr),
804                              omap_bandgap_tshut_irq_handler,
805                              IRQF_TRIGGER_RISING, "tshut",
806                              NULL);
807         if (status) {
808                 gpio_free(gpio_nr);
809                 dev_err(bg_ptr->dev, "request irq failed for TSHUT");
810         }
811
812         return 0;
813 }
814
815 /* Initialization of Talert. Call it only if HAS(TALERT) is set */
816 static int omap_bandgap_talert_init(struct omap_bandgap *bg_ptr,
817                                     struct platform_device *pdev)
818 {
819         int ret;
820
821         bg_ptr->irq = platform_get_irq(pdev, 0);
822         if (bg_ptr->irq < 0) {
823                 dev_err(&pdev->dev, "get_irq failed\n");
824                 return bg_ptr->irq;
825         }
826         ret = request_threaded_irq(bg_ptr->irq, NULL,
827                                    omap_bandgap_talert_irq_handler,
828                                    IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
829                                    "talert", bg_ptr);
830         if (ret) {
831                 dev_err(&pdev->dev, "Request threaded irq failed.\n");
832                 return ret;
833         }
834
835         return 0;
836 }
837
838 static const struct of_device_id of_omap_bandgap_match[];
839 static struct omap_bandgap *omap_bandgap_build(struct platform_device *pdev)
840 {
841         struct device_node *node = pdev->dev.of_node;
842         const struct of_device_id *of_id;
843         struct omap_bandgap *bg_ptr;
844         struct resource *res;
845         u32 prop;
846         int i;
847
848         /* just for the sake */
849         if (!node) {
850                 dev_err(&pdev->dev, "no platform information available\n");
851                 return ERR_PTR(-EINVAL);
852         }
853
854         bg_ptr = devm_kzalloc(&pdev->dev, sizeof(struct omap_bandgap),
855                                     GFP_KERNEL);
856         if (!bg_ptr) {
857                 dev_err(&pdev->dev, "Unable to allocate mem for driver ref\n");
858                 return ERR_PTR(-ENOMEM);
859         }
860
861         of_id = of_match_device(of_omap_bandgap_match, &pdev->dev);
862         if (of_id)
863                 bg_ptr->conf = of_id->data;
864
865         i = 0;
866         do {
867                 void __iomem *chunk;
868
869                 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
870                 if (!res)
871                         break;
872                 chunk = devm_ioremap_resource(&pdev->dev, res);
873                 if (i == 0)
874                         bg_ptr->base = chunk;
875                 if (IS_ERR(chunk))
876                         return ERR_CAST(chunk);
877
878                 i++;
879         } while (res);
880
881         if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT)) {
882                 if (of_property_read_u32(node, "ti,tshut-gpio", &prop) < 0) {
883                         dev_err(&pdev->dev, "missing tshut gpio in device tree\n");
884                         return ERR_PTR(-EINVAL);
885                 }
886                 bg_ptr->tshut_gpio = prop;
887                 if (!gpio_is_valid(bg_ptr->tshut_gpio)) {
888                         dev_err(&pdev->dev, "invalid gpio for tshut (%d)\n",
889                                 bg_ptr->tshut_gpio);
890                         return ERR_PTR(-EINVAL);
891                 }
892         }
893
894         return bg_ptr;
895 }
896
897 static
898 int omap_bandgap_probe(struct platform_device *pdev)
899 {
900         struct omap_bandgap *bg_ptr;
901         int clk_rate, ret = 0, i;
902
903         bg_ptr = omap_bandgap_build(pdev);
904         if (IS_ERR_OR_NULL(bg_ptr)) {
905                 dev_err(&pdev->dev, "failed to fetch platform data\n");
906                 return PTR_ERR(bg_ptr);
907         }
908         bg_ptr->dev = &pdev->dev;
909
910         if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT)) {
911                 ret = omap_bandgap_tshut_init(bg_ptr, pdev);
912                 if (ret) {
913                         dev_err(&pdev->dev,
914                                 "failed to initialize system tshut IRQ\n");
915                         return ret;
916                 }
917         }
918
919         bg_ptr->fclock = clk_get(NULL, bg_ptr->conf->fclock_name);
920         ret = IS_ERR_OR_NULL(bg_ptr->fclock);
921         if (ret) {
922                 dev_err(&pdev->dev, "failed to request fclock reference\n");
923                 goto free_irqs;
924         }
925
926         bg_ptr->div_clk = clk_get(NULL,  bg_ptr->conf->div_ck_name);
927         ret = IS_ERR_OR_NULL(bg_ptr->div_clk);
928         if (ret) {
929                 dev_err(&pdev->dev,
930                         "failed to request div_ts_ck clock ref\n");
931                 goto free_irqs;
932         }
933
934         for (i = 0; i < bg_ptr->conf->sensor_count; i++) {
935                 struct temp_sensor_registers *tsr;
936                 u32 val;
937
938                 tsr = bg_ptr->conf->sensors[i].registers;
939                 /*
940                  * check if the efuse has a non-zero value if not
941                  * it is an untrimmed sample and the temperatures
942                  * may not be accurate
943                  */
944                 val = omap_bandgap_readl(bg_ptr, tsr->bgap_efuse);
945                 if (ret || !val)
946                         dev_info(&pdev->dev,
947                                  "Non-trimmed BGAP, Temp not accurate\n");
948         }
949
950         clk_rate = clk_round_rate(bg_ptr->div_clk,
951                                   bg_ptr->conf->sensors[0].ts_data->max_freq);
952         if (clk_rate < bg_ptr->conf->sensors[0].ts_data->min_freq ||
953             clk_rate == 0xffffffff) {
954                 ret = -ENODEV;
955                 dev_err(&pdev->dev, "wrong clock rate (%d)\n", clk_rate);
956                 goto put_clks;
957         }
958
959         ret = clk_set_rate(bg_ptr->div_clk, clk_rate);
960         if (ret)
961                 dev_err(&pdev->dev, "Cannot re-set clock rate. Continuing\n");
962
963         bg_ptr->clk_rate = clk_rate;
964         if (OMAP_BANDGAP_HAS(bg_ptr, CLK_CTRL))
965                 clk_prepare_enable(bg_ptr->fclock);
966
967
968         mutex_init(&bg_ptr->bg_mutex);
969         bg_ptr->dev = &pdev->dev;
970         platform_set_drvdata(pdev, bg_ptr);
971
972         omap_bandgap_power(bg_ptr, true);
973
974         /* Set default counter to 1 for now */
975         if (OMAP_BANDGAP_HAS(bg_ptr, COUNTER))
976                 for (i = 0; i < bg_ptr->conf->sensor_count; i++)
977                         RMW_BITS(bg_ptr, i, bgap_counter, counter_mask, 1);
978
979         /* Set default thresholds for alert and shutdown */
980         for (i = 0; i < bg_ptr->conf->sensor_count; i++) {
981                 struct temp_sensor_data *ts_data;
982
983                 ts_data = bg_ptr->conf->sensors[i].ts_data;
984
985                 if (OMAP_BANDGAP_HAS(bg_ptr, TALERT)) {
986                         /* Set initial Talert thresholds */
987                         RMW_BITS(bg_ptr, i, bgap_threshold,
988                                  threshold_tcold_mask, ts_data->t_cold);
989                         RMW_BITS(bg_ptr, i, bgap_threshold,
990                                  threshold_thot_mask, ts_data->t_hot);
991                         /* Enable the alert events */
992                         RMW_BITS(bg_ptr, i, bgap_mask_ctrl, mask_hot_mask, 1);
993                         RMW_BITS(bg_ptr, i, bgap_mask_ctrl, mask_cold_mask, 1);
994                 }
995
996                 if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT_CONFIG)) {
997                         /* Set initial Tshut thresholds */
998                         RMW_BITS(bg_ptr, i, tshut_threshold,
999                                  tshut_hot_mask, ts_data->tshut_hot);
1000                         RMW_BITS(bg_ptr, i, tshut_threshold,
1001                                  tshut_cold_mask, ts_data->tshut_cold);
1002                 }
1003         }
1004
1005         if (OMAP_BANDGAP_HAS(bg_ptr, MODE_CONFIG))
1006                 enable_continuous_mode(bg_ptr);
1007
1008         /* Set .250 seconds time as default counter */
1009         if (OMAP_BANDGAP_HAS(bg_ptr, COUNTER))
1010                 for (i = 0; i < bg_ptr->conf->sensor_count; i++)
1011                         RMW_BITS(bg_ptr, i, bgap_counter, counter_mask,
1012                                  bg_ptr->clk_rate / 4);
1013
1014         /* Every thing is good? Then expose the sensors */
1015         for (i = 0; i < bg_ptr->conf->sensor_count; i++) {
1016                 char *domain;
1017
1018                 if (bg_ptr->conf->sensors[i].register_cooling)
1019                         bg_ptr->conf->sensors[i].register_cooling(bg_ptr, i);
1020
1021                 domain = bg_ptr->conf->sensors[i].domain;
1022                 if (bg_ptr->conf->expose_sensor)
1023                         bg_ptr->conf->expose_sensor(bg_ptr, i, domain);
1024         }
1025
1026         /*
1027          * Enable the Interrupts once everything is set. Otherwise irq handler
1028          * might be called as soon as it is enabled where as rest of framework
1029          * is still getting initialised.
1030          */
1031         if (OMAP_BANDGAP_HAS(bg_ptr, TALERT)) {
1032                 ret = omap_bandgap_talert_init(bg_ptr, pdev);
1033                 if (ret) {
1034                         dev_err(&pdev->dev, "failed to initialize Talert IRQ\n");
1035                         i = bg_ptr->conf->sensor_count;
1036                         goto disable_clk;
1037                 }
1038         }
1039
1040         return 0;
1041
1042 disable_clk:
1043         if (OMAP_BANDGAP_HAS(bg_ptr, CLK_CTRL))
1044                 clk_disable_unprepare(bg_ptr->fclock);
1045 put_clks:
1046         clk_put(bg_ptr->fclock);
1047         clk_put(bg_ptr->div_clk);
1048 free_irqs:
1049         if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT)) {
1050                 free_irq(gpio_to_irq(bg_ptr->tshut_gpio), NULL);
1051                 gpio_free(bg_ptr->tshut_gpio);
1052         }
1053
1054         return ret;
1055 }
1056
1057 static
1058 int omap_bandgap_remove(struct platform_device *pdev)
1059 {
1060         struct omap_bandgap *bg_ptr = platform_get_drvdata(pdev);
1061         int i;
1062
1063         /* First thing is to remove sensor interfaces */
1064         for (i = 0; i < bg_ptr->conf->sensor_count; i++) {
1065                 if (bg_ptr->conf->sensors[i].register_cooling)
1066                         bg_ptr->conf->sensors[i].unregister_cooling(bg_ptr, i);
1067
1068                 if (bg_ptr->conf->remove_sensor)
1069                         bg_ptr->conf->remove_sensor(bg_ptr, i);
1070         }
1071
1072         omap_bandgap_power(bg_ptr, false);
1073
1074         if (OMAP_BANDGAP_HAS(bg_ptr, CLK_CTRL))
1075                 clk_disable_unprepare(bg_ptr->fclock);
1076         clk_put(bg_ptr->fclock);
1077         clk_put(bg_ptr->div_clk);
1078
1079         if (OMAP_BANDGAP_HAS(bg_ptr, TALERT))
1080                 free_irq(bg_ptr->irq, bg_ptr);
1081
1082         if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT)) {
1083                 free_irq(gpio_to_irq(bg_ptr->tshut_gpio), NULL);
1084                 gpio_free(bg_ptr->tshut_gpio);
1085         }
1086
1087         return 0;
1088 }
1089
1090 #ifdef CONFIG_PM
1091 static int omap_bandgap_save_ctxt(struct omap_bandgap *bg_ptr)
1092 {
1093         int i;
1094
1095         for (i = 0; i < bg_ptr->conf->sensor_count; i++) {
1096                 struct temp_sensor_registers *tsr;
1097                 struct temp_sensor_regval *rval;
1098
1099                 rval = &bg_ptr->conf->sensors[i].regval;
1100                 tsr = bg_ptr->conf->sensors[i].registers;
1101
1102                 if (OMAP_BANDGAP_HAS(bg_ptr, MODE_CONFIG))
1103                         rval->bg_mode_ctrl = omap_bandgap_readl(bg_ptr,
1104                                                         tsr->bgap_mode_ctrl);
1105                 if (OMAP_BANDGAP_HAS(bg_ptr, COUNTER))
1106                         rval->bg_counter = omap_bandgap_readl(bg_ptr,
1107                                                         tsr->bgap_counter);
1108                 if (OMAP_BANDGAP_HAS(bg_ptr, TALERT)) {
1109                         rval->bg_threshold = omap_bandgap_readl(bg_ptr,
1110                                                         tsr->bgap_threshold);
1111                         rval->bg_ctrl = omap_bandgap_readl(bg_ptr,
1112                                                    tsr->bgap_mask_ctrl);
1113                 }
1114
1115                 if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT_CONFIG))
1116                         rval->tshut_threshold = omap_bandgap_readl(bg_ptr,
1117                                                    tsr->tshut_threshold);
1118         }
1119
1120         return 0;
1121 }
1122
1123 static int omap_bandgap_restore_ctxt(struct omap_bandgap *bg_ptr)
1124 {
1125         int i;
1126
1127         for (i = 0; i < bg_ptr->conf->sensor_count; i++) {
1128                 struct temp_sensor_registers *tsr;
1129                 struct temp_sensor_regval *rval;
1130                 u32 val = 0;
1131
1132                 rval = &bg_ptr->conf->sensors[i].regval;
1133                 tsr = bg_ptr->conf->sensors[i].registers;
1134
1135                 if (OMAP_BANDGAP_HAS(bg_ptr, COUNTER))
1136                         val = omap_bandgap_readl(bg_ptr, tsr->bgap_counter);
1137
1138                 if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT_CONFIG))
1139                         omap_bandgap_writel(bg_ptr, rval->tshut_threshold,
1140                                             tsr->tshut_threshold);
1141                 /* Force immediate temperature measurement and update
1142                  * of the DTEMP field
1143                  */
1144                 omap_bandgap_force_single_read(bg_ptr, i);
1145
1146                 if (OMAP_BANDGAP_HAS(bg_ptr, COUNTER))
1147                         omap_bandgap_writel(bg_ptr, rval->bg_counter,
1148                                             tsr->bgap_counter);
1149                 if (OMAP_BANDGAP_HAS(bg_ptr, MODE_CONFIG))
1150                         omap_bandgap_writel(bg_ptr, rval->bg_mode_ctrl,
1151                                             tsr->bgap_mode_ctrl);
1152                 if (OMAP_BANDGAP_HAS(bg_ptr, TALERT)) {
1153                         omap_bandgap_writel(bg_ptr, rval->bg_threshold,
1154                                             tsr->bgap_threshold);
1155                         omap_bandgap_writel(bg_ptr, rval->bg_ctrl,
1156                                             tsr->bgap_mask_ctrl);
1157                 }
1158         }
1159
1160         return 0;
1161 }
1162
1163 static int omap_bandgap_suspend(struct device *dev)
1164 {
1165         struct omap_bandgap *bg_ptr = dev_get_drvdata(dev);
1166         int err;
1167
1168         err = omap_bandgap_save_ctxt(bg_ptr);
1169         omap_bandgap_power(bg_ptr, false);
1170
1171         if (OMAP_BANDGAP_HAS(bg_ptr, CLK_CTRL))
1172                 clk_disable_unprepare(bg_ptr->fclock);
1173
1174         return err;
1175 }
1176
1177 static int omap_bandgap_resume(struct device *dev)
1178 {
1179         struct omap_bandgap *bg_ptr = dev_get_drvdata(dev);
1180
1181         if (OMAP_BANDGAP_HAS(bg_ptr, CLK_CTRL))
1182                 clk_prepare_enable(bg_ptr->fclock);
1183
1184         omap_bandgap_power(bg_ptr, true);
1185
1186         return omap_bandgap_restore_ctxt(bg_ptr);
1187 }
1188 static const struct dev_pm_ops omap_bandgap_dev_pm_ops = {
1189         SET_SYSTEM_SLEEP_PM_OPS(omap_bandgap_suspend,
1190                                 omap_bandgap_resume)
1191 };
1192
1193 #define DEV_PM_OPS      (&omap_bandgap_dev_pm_ops)
1194 #else
1195 #define DEV_PM_OPS      NULL
1196 #endif
1197
1198 static const struct of_device_id of_omap_bandgap_match[] = {
1199 #ifdef CONFIG_OMAP4_THERMAL
1200         {
1201                 .compatible = "ti,omap4430-bandgap",
1202                 .data = (void *)&omap4430_data,
1203         },
1204         {
1205                 .compatible = "ti,omap4460-bandgap",
1206                 .data = (void *)&omap4460_data,
1207         },
1208         {
1209                 .compatible = "ti,omap4470-bandgap",
1210                 .data = (void *)&omap4470_data,
1211         },
1212 #endif
1213 #ifdef CONFIG_OMAP5_THERMAL
1214         {
1215                 .compatible = "ti,omap5430-bandgap",
1216                 .data = (void *)&omap5430_data,
1217         },
1218 #endif
1219         /* Sentinel */
1220         { },
1221 };
1222 MODULE_DEVICE_TABLE(of, of_omap_bandgap_match);
1223
1224 static struct platform_driver omap_bandgap_sensor_driver = {
1225         .probe = omap_bandgap_probe,
1226         .remove = omap_bandgap_remove,
1227         .driver = {
1228                         .name = "omap-bandgap",
1229                         .pm = DEV_PM_OPS,
1230                         .of_match_table = of_omap_bandgap_match,
1231         },
1232 };
1233
1234 module_platform_driver(omap_bandgap_sensor_driver);
1235
1236 MODULE_DESCRIPTION("OMAP4+ bandgap temperature sensor driver");
1237 MODULE_LICENSE("GPL v2");
1238 MODULE_ALIAS("platform:omap-bandgap");
1239 MODULE_AUTHOR("Texas Instrument Inc.");