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