1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * TI Bandgap temperature sensor driver |
4 | * |
5 | * Copyright (C) 2011-2012 Texas Instruments Incorporated - http://www.ti.com/ |
6 | * Author: J Keerthy <j-keerthy@ti.com> |
7 | * Author: Moiz Sonasath <m-sonasath@ti.com> |
8 | * Couple of fixes, DT and MFD adaptation: |
9 | * Eduardo Valentin <eduardo.valentin@ti.com> |
10 | */ |
11 | |
12 | #include <linux/clk.h> |
13 | #include <linux/cpu_pm.h> |
14 | #include <linux/device.h> |
15 | #include <linux/err.h> |
16 | #include <linux/export.h> |
17 | #include <linux/gpio/consumer.h> |
18 | #include <linux/init.h> |
19 | #include <linux/interrupt.h> |
20 | #include <linux/io.h> |
21 | #include <linux/iopoll.h> |
22 | #include <linux/kernel.h> |
23 | #include <linux/module.h> |
24 | #include <linux/of.h> |
25 | #include <linux/of_device.h> |
26 | #include <linux/of_irq.h> |
27 | #include <linux/of_platform.h> |
28 | #include <linux/platform_device.h> |
29 | #include <linux/pm.h> |
30 | #include <linux/pm_runtime.h> |
31 | #include <linux/reboot.h> |
32 | #include <linux/spinlock.h> |
33 | #include <linux/sys_soc.h> |
34 | #include <linux/types.h> |
35 | |
36 | #include "ti-bandgap.h" |
37 | |
38 | static int ti_bandgap_force_single_read(struct ti_bandgap *bgp, int id); |
39 | #ifdef CONFIG_PM_SLEEP |
40 | static int bandgap_omap_cpu_notifier(struct notifier_block *nb, |
41 | unsigned long cmd, void *v); |
42 | #endif |
43 | |
44 | /*** Helper functions to access registers and their bitfields ***/ |
45 | |
46 | /** |
47 | * ti_bandgap_readl() - simple read helper function |
48 | * @bgp: pointer to ti_bandgap structure |
49 | * @reg: desired register (offset) to be read |
50 | * |
51 | * Helper function to read bandgap registers. It uses the io remapped area. |
52 | * Return: the register value. |
53 | */ |
54 | static u32 ti_bandgap_readl(struct ti_bandgap *bgp, u32 reg) |
55 | { |
56 | return readl(addr: bgp->base + reg); |
57 | } |
58 | |
59 | /** |
60 | * ti_bandgap_writel() - simple write helper function |
61 | * @bgp: pointer to ti_bandgap structure |
62 | * @val: desired register value to be written |
63 | * @reg: desired register (offset) to be written |
64 | * |
65 | * Helper function to write bandgap registers. It uses the io remapped area. |
66 | */ |
67 | static void ti_bandgap_writel(struct ti_bandgap *bgp, u32 val, u32 reg) |
68 | { |
69 | writel(val, addr: bgp->base + reg); |
70 | } |
71 | |
72 | /** |
73 | * DOC: macro to update bits. |
74 | * |
75 | * RMW_BITS() - used to read, modify and update bandgap bitfields. |
76 | * The value passed will be shifted. |
77 | */ |
78 | #define RMW_BITS(bgp, id, reg, mask, val) \ |
79 | do { \ |
80 | struct temp_sensor_registers *t; \ |
81 | u32 r; \ |
82 | \ |
83 | t = bgp->conf->sensors[(id)].registers; \ |
84 | r = ti_bandgap_readl(bgp, t->reg); \ |
85 | r &= ~t->mask; \ |
86 | r |= (val) << __ffs(t->mask); \ |
87 | ti_bandgap_writel(bgp, r, t->reg); \ |
88 | } while (0) |
89 | |
90 | /*** Basic helper functions ***/ |
91 | |
92 | /** |
93 | * ti_bandgap_power() - controls the power state of a bandgap device |
94 | * @bgp: pointer to ti_bandgap structure |
95 | * @on: desired power state (1 - on, 0 - off) |
96 | * |
97 | * Used to power on/off a bandgap device instance. Only used on those |
98 | * that features tempsoff bit. |
99 | * |
100 | * Return: 0 on success, -ENOTSUPP if tempsoff is not supported. |
101 | */ |
102 | static int ti_bandgap_power(struct ti_bandgap *bgp, bool on) |
103 | { |
104 | int i; |
105 | |
106 | if (!TI_BANDGAP_HAS(bgp, POWER_SWITCH)) |
107 | return -ENOTSUPP; |
108 | |
109 | for (i = 0; i < bgp->conf->sensor_count; i++) |
110 | /* active on 0 */ |
111 | RMW_BITS(bgp, i, temp_sensor_ctrl, bgap_tempsoff_mask, !on); |
112 | return 0; |
113 | } |
114 | |
115 | /** |
116 | * ti_errata814_bandgap_read_temp() - helper function to read dra7 sensor temperature |
117 | * @bgp: pointer to ti_bandgap structure |
118 | * @reg: desired register (offset) to be read |
119 | * |
120 | * Function to read dra7 bandgap sensor temperature. This is done separately |
121 | * so as to workaround the errata "Bandgap Temperature read Dtemp can be |
122 | * corrupted" - Errata ID: i814". |
123 | * Read accesses to registers listed below can be corrupted due to incorrect |
124 | * resynchronization between clock domains. |
125 | * Read access to registers below can be corrupted : |
126 | * CTRL_CORE_DTEMP_MPU/GPU/CORE/DSPEVE/IVA_n (n = 0 to 4) |
127 | * CTRL_CORE_TEMP_SENSOR_MPU/GPU/CORE/DSPEVE/IVA_n |
128 | * |
129 | * Return: the register value. |
130 | */ |
131 | static u32 ti_errata814_bandgap_read_temp(struct ti_bandgap *bgp, u32 reg) |
132 | { |
133 | u32 val1, val2; |
134 | |
135 | val1 = ti_bandgap_readl(bgp, reg); |
136 | val2 = ti_bandgap_readl(bgp, reg); |
137 | |
138 | /* If both times we read the same value then that is right */ |
139 | if (val1 == val2) |
140 | return val1; |
141 | |
142 | /* if val1 and val2 are different read it third time */ |
143 | return ti_bandgap_readl(bgp, reg); |
144 | } |
145 | |
146 | /** |
147 | * ti_bandgap_read_temp() - helper function to read sensor temperature |
148 | * @bgp: pointer to ti_bandgap structure |
149 | * @id: bandgap sensor id |
150 | * |
151 | * Function to concentrate the steps to read sensor temperature register. |
152 | * This function is desired because, depending on bandgap device version, |
153 | * it might be needed to freeze the bandgap state machine, before fetching |
154 | * the register value. |
155 | * |
156 | * Return: temperature in ADC values. |
157 | */ |
158 | static u32 ti_bandgap_read_temp(struct ti_bandgap *bgp, int id) |
159 | { |
160 | struct temp_sensor_registers *tsr; |
161 | u32 temp, reg; |
162 | |
163 | tsr = bgp->conf->sensors[id].registers; |
164 | reg = tsr->temp_sensor_ctrl; |
165 | |
166 | if (TI_BANDGAP_HAS(bgp, FREEZE_BIT)) { |
167 | RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 1); |
168 | /* |
169 | * In case we cannot read from cur_dtemp / dtemp_0, |
170 | * then we read from the last valid temp read |
171 | */ |
172 | reg = tsr->ctrl_dtemp_1; |
173 | } |
174 | |
175 | /* read temperature */ |
176 | if (TI_BANDGAP_HAS(bgp, ERRATA_814)) |
177 | temp = ti_errata814_bandgap_read_temp(bgp, reg); |
178 | else |
179 | temp = ti_bandgap_readl(bgp, reg); |
180 | |
181 | temp &= tsr->bgap_dtemp_mask; |
182 | |
183 | if (TI_BANDGAP_HAS(bgp, FREEZE_BIT)) |
184 | RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 0); |
185 | |
186 | return temp; |
187 | } |
188 | |
189 | /*** IRQ handlers ***/ |
190 | |
191 | /** |
192 | * ti_bandgap_talert_irq_handler() - handles Temperature alert IRQs |
193 | * @irq: IRQ number |
194 | * @data: private data (struct ti_bandgap *) |
195 | * |
196 | * This is the Talert handler. Use it only if bandgap device features |
197 | * HAS(TALERT). This handler goes over all sensors and checks their |
198 | * conditions and acts accordingly. In case there are events pending, |
199 | * it will reset the event mask to wait for the opposite event (next event). |
200 | * Every time there is a new event, it will be reported to thermal layer. |
201 | * |
202 | * Return: IRQ_HANDLED |
203 | */ |
204 | static irqreturn_t ti_bandgap_talert_irq_handler(int irq, void *data) |
205 | { |
206 | struct ti_bandgap *bgp = data; |
207 | struct temp_sensor_registers *tsr; |
208 | u32 t_hot = 0, t_cold = 0, ctrl; |
209 | int i; |
210 | |
211 | spin_lock(lock: &bgp->lock); |
212 | for (i = 0; i < bgp->conf->sensor_count; i++) { |
213 | tsr = bgp->conf->sensors[i].registers; |
214 | ctrl = ti_bandgap_readl(bgp, reg: tsr->bgap_status); |
215 | |
216 | /* Read the status of t_hot */ |
217 | t_hot = ctrl & tsr->status_hot_mask; |
218 | |
219 | /* Read the status of t_cold */ |
220 | t_cold = ctrl & tsr->status_cold_mask; |
221 | |
222 | if (!t_cold && !t_hot) |
223 | continue; |
224 | |
225 | ctrl = ti_bandgap_readl(bgp, reg: tsr->bgap_mask_ctrl); |
226 | /* |
227 | * One TALERT interrupt: Two sources |
228 | * If the interrupt is due to t_hot then mask t_hot and |
229 | * unmask t_cold else mask t_cold and unmask t_hot |
230 | */ |
231 | if (t_hot) { |
232 | ctrl &= ~tsr->mask_hot_mask; |
233 | ctrl |= tsr->mask_cold_mask; |
234 | } else if (t_cold) { |
235 | ctrl &= ~tsr->mask_cold_mask; |
236 | ctrl |= tsr->mask_hot_mask; |
237 | } |
238 | |
239 | ti_bandgap_writel(bgp, val: ctrl, reg: tsr->bgap_mask_ctrl); |
240 | |
241 | dev_dbg(bgp->dev, |
242 | "%s: IRQ from %s sensor: hotevent %d coldevent %d\n" , |
243 | __func__, bgp->conf->sensors[i].domain, |
244 | t_hot, t_cold); |
245 | |
246 | /* report temperature to whom may concern */ |
247 | if (bgp->conf->report_temperature) |
248 | bgp->conf->report_temperature(bgp, i); |
249 | } |
250 | spin_unlock(lock: &bgp->lock); |
251 | |
252 | return IRQ_HANDLED; |
253 | } |
254 | |
255 | /** |
256 | * ti_bandgap_tshut_irq_handler() - handles Temperature shutdown signal |
257 | * @irq: IRQ number |
258 | * @data: private data (unused) |
259 | * |
260 | * This is the Tshut handler. Use it only if bandgap device features |
261 | * HAS(TSHUT). If any sensor fires the Tshut signal, we simply shutdown |
262 | * the system. |
263 | * |
264 | * Return: IRQ_HANDLED |
265 | */ |
266 | static irqreturn_t ti_bandgap_tshut_irq_handler(int irq, void *data) |
267 | { |
268 | pr_emerg("%s: TSHUT temperature reached. Needs shut down...\n" , |
269 | __func__); |
270 | |
271 | orderly_poweroff(force: true); |
272 | |
273 | return IRQ_HANDLED; |
274 | } |
275 | |
276 | /*** Helper functions which manipulate conversion ADC <-> mi Celsius ***/ |
277 | |
278 | /** |
279 | * ti_bandgap_adc_to_mcelsius() - converts an ADC value to mCelsius scale |
280 | * @bgp: struct ti_bandgap pointer |
281 | * @adc_val: value in ADC representation |
282 | * @t: address where to write the resulting temperature in mCelsius |
283 | * |
284 | * Simple conversion from ADC representation to mCelsius. In case the ADC value |
285 | * is out of the ADC conv table range, it returns -ERANGE, 0 on success. |
286 | * The conversion table is indexed by the ADC values. |
287 | * |
288 | * Return: 0 if conversion was successful, else -ERANGE in case the @adc_val |
289 | * argument is out of the ADC conv table range. |
290 | */ |
291 | static |
292 | int ti_bandgap_adc_to_mcelsius(struct ti_bandgap *bgp, int adc_val, int *t) |
293 | { |
294 | const struct ti_bandgap_data *conf = bgp->conf; |
295 | |
296 | /* look up for temperature in the table and return the temperature */ |
297 | if (adc_val < conf->adc_start_val || adc_val > conf->adc_end_val) |
298 | return -ERANGE; |
299 | |
300 | *t = bgp->conf->conv_table[adc_val - conf->adc_start_val]; |
301 | return 0; |
302 | } |
303 | |
304 | /** |
305 | * ti_bandgap_validate() - helper to check the sanity of a struct ti_bandgap |
306 | * @bgp: struct ti_bandgap pointer |
307 | * @id: bandgap sensor id |
308 | * |
309 | * Checks if the bandgap pointer is valid and if the sensor id is also |
310 | * applicable. |
311 | * |
312 | * Return: 0 if no errors, -EINVAL for invalid @bgp pointer or -ERANGE if |
313 | * @id cannot index @bgp sensors. |
314 | */ |
315 | static inline int ti_bandgap_validate(struct ti_bandgap *bgp, int id) |
316 | { |
317 | if (IS_ERR_OR_NULL(ptr: bgp)) { |
318 | pr_err("%s: invalid bandgap pointer\n" , __func__); |
319 | return -EINVAL; |
320 | } |
321 | |
322 | if ((id < 0) || (id >= bgp->conf->sensor_count)) { |
323 | dev_err(bgp->dev, "%s: sensor id out of range (%d)\n" , |
324 | __func__, id); |
325 | return -ERANGE; |
326 | } |
327 | |
328 | return 0; |
329 | } |
330 | |
331 | /** |
332 | * ti_bandgap_read_counter() - read the sensor counter |
333 | * @bgp: pointer to bandgap instance |
334 | * @id: sensor id |
335 | * @interval: resulting update interval in miliseconds |
336 | */ |
337 | static void ti_bandgap_read_counter(struct ti_bandgap *bgp, int id, |
338 | int *interval) |
339 | { |
340 | struct temp_sensor_registers *tsr; |
341 | int time; |
342 | |
343 | tsr = bgp->conf->sensors[id].registers; |
344 | time = ti_bandgap_readl(bgp, reg: tsr->bgap_counter); |
345 | time = (time & tsr->counter_mask) >> |
346 | __ffs(tsr->counter_mask); |
347 | time = time * 1000 / bgp->clk_rate; |
348 | *interval = time; |
349 | } |
350 | |
351 | /** |
352 | * ti_bandgap_read_counter_delay() - read the sensor counter delay |
353 | * @bgp: pointer to bandgap instance |
354 | * @id: sensor id |
355 | * @interval: resulting update interval in miliseconds |
356 | */ |
357 | static void ti_bandgap_read_counter_delay(struct ti_bandgap *bgp, int id, |
358 | int *interval) |
359 | { |
360 | struct temp_sensor_registers *tsr; |
361 | int reg_val; |
362 | |
363 | tsr = bgp->conf->sensors[id].registers; |
364 | |
365 | reg_val = ti_bandgap_readl(bgp, reg: tsr->bgap_mask_ctrl); |
366 | reg_val = (reg_val & tsr->mask_counter_delay_mask) >> |
367 | __ffs(tsr->mask_counter_delay_mask); |
368 | switch (reg_val) { |
369 | case 0: |
370 | *interval = 0; |
371 | break; |
372 | case 1: |
373 | *interval = 1; |
374 | break; |
375 | case 2: |
376 | *interval = 10; |
377 | break; |
378 | case 3: |
379 | *interval = 100; |
380 | break; |
381 | case 4: |
382 | *interval = 250; |
383 | break; |
384 | case 5: |
385 | *interval = 500; |
386 | break; |
387 | default: |
388 | dev_warn(bgp->dev, "Wrong counter delay value read from register %X" , |
389 | reg_val); |
390 | } |
391 | } |
392 | |
393 | /** |
394 | * ti_bandgap_read_update_interval() - read the sensor update interval |
395 | * @bgp: pointer to bandgap instance |
396 | * @id: sensor id |
397 | * @interval: resulting update interval in miliseconds |
398 | * |
399 | * Return: 0 on success or the proper error code |
400 | */ |
401 | int ti_bandgap_read_update_interval(struct ti_bandgap *bgp, int id, |
402 | int *interval) |
403 | { |
404 | int ret = 0; |
405 | |
406 | ret = ti_bandgap_validate(bgp, id); |
407 | if (ret) |
408 | goto exit; |
409 | |
410 | if (!TI_BANDGAP_HAS(bgp, COUNTER) && |
411 | !TI_BANDGAP_HAS(bgp, COUNTER_DELAY)) { |
412 | ret = -ENOTSUPP; |
413 | goto exit; |
414 | } |
415 | |
416 | if (TI_BANDGAP_HAS(bgp, COUNTER)) { |
417 | ti_bandgap_read_counter(bgp, id, interval); |
418 | goto exit; |
419 | } |
420 | |
421 | ti_bandgap_read_counter_delay(bgp, id, interval); |
422 | exit: |
423 | return ret; |
424 | } |
425 | |
426 | /** |
427 | * ti_bandgap_write_counter_delay() - set the counter_delay |
428 | * @bgp: pointer to bandgap instance |
429 | * @id: sensor id |
430 | * @interval: desired update interval in miliseconds |
431 | * |
432 | * Return: 0 on success or the proper error code |
433 | */ |
434 | static int ti_bandgap_write_counter_delay(struct ti_bandgap *bgp, int id, |
435 | u32 interval) |
436 | { |
437 | int rval; |
438 | |
439 | switch (interval) { |
440 | case 0: /* Immediate conversion */ |
441 | rval = 0x0; |
442 | break; |
443 | case 1: /* Conversion after ever 1ms */ |
444 | rval = 0x1; |
445 | break; |
446 | case 10: /* Conversion after ever 10ms */ |
447 | rval = 0x2; |
448 | break; |
449 | case 100: /* Conversion after ever 100ms */ |
450 | rval = 0x3; |
451 | break; |
452 | case 250: /* Conversion after ever 250ms */ |
453 | rval = 0x4; |
454 | break; |
455 | case 500: /* Conversion after ever 500ms */ |
456 | rval = 0x5; |
457 | break; |
458 | default: |
459 | dev_warn(bgp->dev, "Delay %d ms is not supported\n" , interval); |
460 | return -EINVAL; |
461 | } |
462 | |
463 | spin_lock(lock: &bgp->lock); |
464 | RMW_BITS(bgp, id, bgap_mask_ctrl, mask_counter_delay_mask, rval); |
465 | spin_unlock(lock: &bgp->lock); |
466 | |
467 | return 0; |
468 | } |
469 | |
470 | /** |
471 | * ti_bandgap_write_counter() - set the bandgap sensor counter |
472 | * @bgp: pointer to bandgap instance |
473 | * @id: sensor id |
474 | * @interval: desired update interval in miliseconds |
475 | */ |
476 | static void ti_bandgap_write_counter(struct ti_bandgap *bgp, int id, |
477 | u32 interval) |
478 | { |
479 | interval = interval * bgp->clk_rate / 1000; |
480 | spin_lock(lock: &bgp->lock); |
481 | RMW_BITS(bgp, id, bgap_counter, counter_mask, interval); |
482 | spin_unlock(lock: &bgp->lock); |
483 | } |
484 | |
485 | /** |
486 | * ti_bandgap_write_update_interval() - set the update interval |
487 | * @bgp: pointer to bandgap instance |
488 | * @id: sensor id |
489 | * @interval: desired update interval in miliseconds |
490 | * |
491 | * Return: 0 on success or the proper error code |
492 | */ |
493 | int ti_bandgap_write_update_interval(struct ti_bandgap *bgp, |
494 | int id, u32 interval) |
495 | { |
496 | int ret = ti_bandgap_validate(bgp, id); |
497 | if (ret) |
498 | goto exit; |
499 | |
500 | if (!TI_BANDGAP_HAS(bgp, COUNTER) && |
501 | !TI_BANDGAP_HAS(bgp, COUNTER_DELAY)) { |
502 | ret = -ENOTSUPP; |
503 | goto exit; |
504 | } |
505 | |
506 | if (TI_BANDGAP_HAS(bgp, COUNTER)) { |
507 | ti_bandgap_write_counter(bgp, id, interval); |
508 | goto exit; |
509 | } |
510 | |
511 | ret = ti_bandgap_write_counter_delay(bgp, id, interval); |
512 | exit: |
513 | return ret; |
514 | } |
515 | |
516 | /** |
517 | * ti_bandgap_read_temperature() - report current temperature |
518 | * @bgp: pointer to bandgap instance |
519 | * @id: sensor id |
520 | * @temperature: resulting temperature |
521 | * |
522 | * Return: 0 on success or the proper error code |
523 | */ |
524 | int ti_bandgap_read_temperature(struct ti_bandgap *bgp, int id, |
525 | int *temperature) |
526 | { |
527 | u32 temp; |
528 | int ret; |
529 | |
530 | ret = ti_bandgap_validate(bgp, id); |
531 | if (ret) |
532 | return ret; |
533 | |
534 | if (!TI_BANDGAP_HAS(bgp, MODE_CONFIG)) { |
535 | ret = ti_bandgap_force_single_read(bgp, id); |
536 | if (ret) |
537 | return ret; |
538 | } |
539 | |
540 | spin_lock(lock: &bgp->lock); |
541 | temp = ti_bandgap_read_temp(bgp, id); |
542 | spin_unlock(lock: &bgp->lock); |
543 | |
544 | ret = ti_bandgap_adc_to_mcelsius(bgp, adc_val: temp, t: &temp); |
545 | if (ret) |
546 | return -EIO; |
547 | |
548 | *temperature = temp; |
549 | |
550 | return 0; |
551 | } |
552 | |
553 | /** |
554 | * ti_bandgap_set_sensor_data() - helper function to store thermal |
555 | * framework related data. |
556 | * @bgp: pointer to bandgap instance |
557 | * @id: sensor id |
558 | * @data: thermal framework related data to be stored |
559 | * |
560 | * Return: 0 on success or the proper error code |
561 | */ |
562 | int ti_bandgap_set_sensor_data(struct ti_bandgap *bgp, int id, void *data) |
563 | { |
564 | int ret = ti_bandgap_validate(bgp, id); |
565 | if (ret) |
566 | return ret; |
567 | |
568 | bgp->regval[id].data = data; |
569 | |
570 | return 0; |
571 | } |
572 | |
573 | /** |
574 | * ti_bandgap_get_sensor_data() - helper function to get thermal |
575 | * framework related data. |
576 | * @bgp: pointer to bandgap instance |
577 | * @id: sensor id |
578 | * |
579 | * Return: data stored by set function with sensor id on success or NULL |
580 | */ |
581 | void *ti_bandgap_get_sensor_data(struct ti_bandgap *bgp, int id) |
582 | { |
583 | int ret = ti_bandgap_validate(bgp, id); |
584 | if (ret) |
585 | return ERR_PTR(error: ret); |
586 | |
587 | return bgp->regval[id].data; |
588 | } |
589 | |
590 | /*** Helper functions used during device initialization ***/ |
591 | |
592 | /** |
593 | * ti_bandgap_force_single_read() - executes 1 single ADC conversion |
594 | * @bgp: pointer to struct ti_bandgap |
595 | * @id: sensor id which it is desired to read 1 temperature |
596 | * |
597 | * Used to initialize the conversion state machine and set it to a valid |
598 | * state. Called during device initialization and context restore events. |
599 | * |
600 | * Return: 0 |
601 | */ |
602 | static int |
603 | ti_bandgap_force_single_read(struct ti_bandgap *bgp, int id) |
604 | { |
605 | struct temp_sensor_registers *tsr = bgp->conf->sensors[id].registers; |
606 | void __iomem *temp_sensor_ctrl = bgp->base + tsr->temp_sensor_ctrl; |
607 | int error; |
608 | u32 val; |
609 | |
610 | /* Select continuous or single conversion mode */ |
611 | if (TI_BANDGAP_HAS(bgp, MODE_CONFIG)) { |
612 | if (TI_BANDGAP_HAS(bgp, CONT_MODE_ONLY)) |
613 | RMW_BITS(bgp, id, bgap_mode_ctrl, mode_ctrl_mask, 1); |
614 | else |
615 | RMW_BITS(bgp, id, bgap_mode_ctrl, mode_ctrl_mask, 0); |
616 | } |
617 | |
618 | /* Set Start of Conversion if available */ |
619 | if (tsr->bgap_soc_mask) { |
620 | RMW_BITS(bgp, id, temp_sensor_ctrl, bgap_soc_mask, 1); |
621 | |
622 | /* Wait for EOCZ going up */ |
623 | error = readl_poll_timeout_atomic(temp_sensor_ctrl, val, |
624 | val & tsr->bgap_eocz_mask, |
625 | 1, 1000); |
626 | if (error) |
627 | dev_warn(bgp->dev, "eocz timed out waiting high\n" ); |
628 | |
629 | /* Clear Start of Conversion if available */ |
630 | RMW_BITS(bgp, id, temp_sensor_ctrl, bgap_soc_mask, 0); |
631 | } |
632 | |
633 | /* Wait for EOCZ going down, always needed even if no bgap_soc_mask */ |
634 | error = readl_poll_timeout_atomic(temp_sensor_ctrl, val, |
635 | !(val & tsr->bgap_eocz_mask), |
636 | 1, 1500); |
637 | if (error) |
638 | dev_warn(bgp->dev, "eocz timed out waiting low\n" ); |
639 | |
640 | return 0; |
641 | } |
642 | |
643 | /** |
644 | * ti_bandgap_set_continuous_mode() - One time enabling of continuous mode |
645 | * @bgp: pointer to struct ti_bandgap |
646 | * |
647 | * Call this function only if HAS(MODE_CONFIG) is set. As this driver may |
648 | * be used for junction temperature monitoring, it is desirable that the |
649 | * sensors are operational all the time, so that alerts are generated |
650 | * properly. |
651 | * |
652 | * Return: 0 |
653 | */ |
654 | static int ti_bandgap_set_continuous_mode(struct ti_bandgap *bgp) |
655 | { |
656 | int i; |
657 | |
658 | for (i = 0; i < bgp->conf->sensor_count; i++) { |
659 | /* Perform a single read just before enabling continuous */ |
660 | ti_bandgap_force_single_read(bgp, id: i); |
661 | RMW_BITS(bgp, i, bgap_mode_ctrl, mode_ctrl_mask, 1); |
662 | } |
663 | |
664 | return 0; |
665 | } |
666 | |
667 | /** |
668 | * ti_bandgap_get_trend() - To fetch the temperature trend of a sensor |
669 | * @bgp: pointer to struct ti_bandgap |
670 | * @id: id of the individual sensor |
671 | * @trend: Pointer to trend. |
672 | * |
673 | * This function needs to be called to fetch the temperature trend of a |
674 | * Particular sensor. The function computes the difference in temperature |
675 | * w.r.t time. For the bandgaps with built in history buffer the temperatures |
676 | * are read from the buffer and for those without the Buffer -ENOTSUPP is |
677 | * returned. |
678 | * |
679 | * Return: 0 if no error, else return corresponding error. If no |
680 | * error then the trend value is passed on to trend parameter |
681 | */ |
682 | int ti_bandgap_get_trend(struct ti_bandgap *bgp, int id, int *trend) |
683 | { |
684 | struct temp_sensor_registers *tsr; |
685 | u32 temp1, temp2, reg1, reg2; |
686 | int t1, t2, interval, ret = 0; |
687 | |
688 | ret = ti_bandgap_validate(bgp, id); |
689 | if (ret) |
690 | goto exit; |
691 | |
692 | if (!TI_BANDGAP_HAS(bgp, HISTORY_BUFFER) || |
693 | !TI_BANDGAP_HAS(bgp, FREEZE_BIT)) { |
694 | ret = -ENOTSUPP; |
695 | goto exit; |
696 | } |
697 | |
698 | spin_lock(lock: &bgp->lock); |
699 | |
700 | tsr = bgp->conf->sensors[id].registers; |
701 | |
702 | /* Freeze and read the last 2 valid readings */ |
703 | RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 1); |
704 | reg1 = tsr->ctrl_dtemp_1; |
705 | reg2 = tsr->ctrl_dtemp_2; |
706 | |
707 | /* read temperature from history buffer */ |
708 | temp1 = ti_bandgap_readl(bgp, reg: reg1); |
709 | temp1 &= tsr->bgap_dtemp_mask; |
710 | |
711 | temp2 = ti_bandgap_readl(bgp, reg: reg2); |
712 | temp2 &= tsr->bgap_dtemp_mask; |
713 | |
714 | /* Convert from adc values to mCelsius temperature */ |
715 | ret = ti_bandgap_adc_to_mcelsius(bgp, adc_val: temp1, t: &t1); |
716 | if (ret) |
717 | goto unfreeze; |
718 | |
719 | ret = ti_bandgap_adc_to_mcelsius(bgp, adc_val: temp2, t: &t2); |
720 | if (ret) |
721 | goto unfreeze; |
722 | |
723 | /* Fetch the update interval */ |
724 | ret = ti_bandgap_read_update_interval(bgp, id, interval: &interval); |
725 | if (ret) |
726 | goto unfreeze; |
727 | |
728 | /* Set the interval to 1 ms if bandgap counter delay is not set */ |
729 | if (interval == 0) |
730 | interval = 1; |
731 | |
732 | *trend = (t1 - t2) / interval; |
733 | |
734 | dev_dbg(bgp->dev, "The temperatures are t1 = %d and t2 = %d and trend =%d\n" , |
735 | t1, t2, *trend); |
736 | |
737 | unfreeze: |
738 | RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 0); |
739 | spin_unlock(lock: &bgp->lock); |
740 | exit: |
741 | return ret; |
742 | } |
743 | |
744 | /** |
745 | * ti_bandgap_tshut_init() - setup and initialize tshut handling |
746 | * @bgp: pointer to struct ti_bandgap |
747 | * @pdev: pointer to device struct platform_device |
748 | * |
749 | * Call this function only in case the bandgap features HAS(TSHUT). |
750 | * In this case, the driver needs to handle the TSHUT signal as an IRQ. |
751 | * The IRQ is wired as a GPIO, and for this purpose, it is required |
752 | * to specify which GPIO line is used. TSHUT IRQ is fired anytime |
753 | * one of the bandgap sensors violates the TSHUT high/hot threshold. |
754 | * And in that case, the system must go off. |
755 | * |
756 | * Return: 0 if no error, else error status |
757 | */ |
758 | static int ti_bandgap_tshut_init(struct ti_bandgap *bgp, |
759 | struct platform_device *pdev) |
760 | { |
761 | int status; |
762 | |
763 | status = request_irq(irq: gpiod_to_irq(desc: bgp->tshut_gpiod), |
764 | handler: ti_bandgap_tshut_irq_handler, |
765 | IRQF_TRIGGER_RISING, name: "tshut" , NULL); |
766 | if (status) |
767 | dev_err(bgp->dev, "request irq failed for TSHUT" ); |
768 | |
769 | return 0; |
770 | } |
771 | |
772 | /** |
773 | * ti_bandgap_talert_init() - setup and initialize talert handling |
774 | * @bgp: pointer to struct ti_bandgap |
775 | * @pdev: pointer to device struct platform_device |
776 | * |
777 | * Call this function only in case the bandgap features HAS(TALERT). |
778 | * In this case, the driver needs to handle the TALERT signals as an IRQs. |
779 | * TALERT is a normal IRQ and it is fired any time thresholds (hot or cold) |
780 | * are violated. In these situation, the driver must reprogram the thresholds, |
781 | * accordingly to specified policy. |
782 | * |
783 | * Return: 0 if no error, else return corresponding error. |
784 | */ |
785 | static int ti_bandgap_talert_init(struct ti_bandgap *bgp, |
786 | struct platform_device *pdev) |
787 | { |
788 | int ret; |
789 | |
790 | bgp->irq = platform_get_irq(pdev, 0); |
791 | if (bgp->irq < 0) |
792 | return bgp->irq; |
793 | |
794 | ret = request_threaded_irq(irq: bgp->irq, NULL, |
795 | thread_fn: ti_bandgap_talert_irq_handler, |
796 | IRQF_TRIGGER_HIGH | IRQF_ONESHOT, |
797 | name: "talert" , dev: bgp); |
798 | if (ret) { |
799 | dev_err(&pdev->dev, "Request threaded irq failed.\n" ); |
800 | return ret; |
801 | } |
802 | |
803 | return 0; |
804 | } |
805 | |
806 | static const struct of_device_id of_ti_bandgap_match[]; |
807 | /** |
808 | * ti_bandgap_build() - parse DT and setup a struct ti_bandgap |
809 | * @pdev: pointer to device struct platform_device |
810 | * |
811 | * Used to read the device tree properties accordingly to the bandgap |
812 | * matching version. Based on bandgap version and its capabilities it |
813 | * will build a struct ti_bandgap out of the required DT entries. |
814 | * |
815 | * Return: valid bandgap structure if successful, else returns ERR_PTR |
816 | * return value must be verified with IS_ERR. |
817 | */ |
818 | static struct ti_bandgap *ti_bandgap_build(struct platform_device *pdev) |
819 | { |
820 | struct device_node *node = pdev->dev.of_node; |
821 | const struct of_device_id *of_id; |
822 | struct ti_bandgap *bgp; |
823 | struct resource *res; |
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(error: -EINVAL); |
830 | } |
831 | |
832 | bgp = devm_kzalloc(dev: &pdev->dev, size: sizeof(*bgp), GFP_KERNEL); |
833 | if (!bgp) |
834 | return ERR_PTR(error: -ENOMEM); |
835 | |
836 | of_id = of_match_device(matches: of_ti_bandgap_match, dev: &pdev->dev); |
837 | if (of_id) |
838 | bgp->conf = of_id->data; |
839 | |
840 | /* register shadow for context save and restore */ |
841 | bgp->regval = devm_kcalloc(dev: &pdev->dev, n: bgp->conf->sensor_count, |
842 | size: sizeof(*bgp->regval), GFP_KERNEL); |
843 | if (!bgp->regval) |
844 | return ERR_PTR(error: -ENOMEM); |
845 | |
846 | i = 0; |
847 | do { |
848 | void __iomem *chunk; |
849 | |
850 | res = platform_get_resource(pdev, IORESOURCE_MEM, i); |
851 | if (!res) |
852 | break; |
853 | chunk = devm_ioremap_resource(dev: &pdev->dev, res); |
854 | if (i == 0) |
855 | bgp->base = chunk; |
856 | if (IS_ERR(ptr: chunk)) |
857 | return ERR_CAST(ptr: chunk); |
858 | |
859 | i++; |
860 | } while (res); |
861 | |
862 | if (TI_BANDGAP_HAS(bgp, TSHUT)) { |
863 | bgp->tshut_gpiod = devm_gpiod_get(dev: &pdev->dev, NULL, flags: GPIOD_IN); |
864 | if (IS_ERR(ptr: bgp->tshut_gpiod)) { |
865 | dev_err(&pdev->dev, "invalid gpio for tshut\n" ); |
866 | return ERR_CAST(ptr: bgp->tshut_gpiod); |
867 | } |
868 | } |
869 | |
870 | return bgp; |
871 | } |
872 | |
873 | /* |
874 | * List of SoCs on which the CPU PM notifier can cause erros on the DTEMP |
875 | * readout. |
876 | * Enabled notifier on these machines results in erroneous, random values which |
877 | * could trigger unexpected thermal shutdown. |
878 | */ |
879 | static const struct soc_device_attribute soc_no_cpu_notifier[] = { |
880 | { .machine = "OMAP4430" }, |
881 | { /* sentinel */ } |
882 | }; |
883 | |
884 | /*** Device driver call backs ***/ |
885 | |
886 | static |
887 | int ti_bandgap_probe(struct platform_device *pdev) |
888 | { |
889 | struct ti_bandgap *bgp; |
890 | int clk_rate, ret, i; |
891 | |
892 | bgp = ti_bandgap_build(pdev); |
893 | if (IS_ERR(ptr: bgp)) { |
894 | dev_err(&pdev->dev, "failed to fetch platform data\n" ); |
895 | return PTR_ERR(ptr: bgp); |
896 | } |
897 | bgp->dev = &pdev->dev; |
898 | |
899 | if (TI_BANDGAP_HAS(bgp, UNRELIABLE)) |
900 | dev_warn(&pdev->dev, |
901 | "This OMAP thermal sensor is unreliable. You've been warned\n" ); |
902 | |
903 | if (TI_BANDGAP_HAS(bgp, TSHUT)) { |
904 | ret = ti_bandgap_tshut_init(bgp, pdev); |
905 | if (ret) { |
906 | dev_err(&pdev->dev, |
907 | "failed to initialize system tshut IRQ\n" ); |
908 | return ret; |
909 | } |
910 | } |
911 | |
912 | bgp->fclock = clk_get(NULL, id: bgp->conf->fclock_name); |
913 | if (IS_ERR(ptr: bgp->fclock)) { |
914 | dev_err(&pdev->dev, "failed to request fclock reference\n" ); |
915 | ret = PTR_ERR(ptr: bgp->fclock); |
916 | goto free_irqs; |
917 | } |
918 | |
919 | bgp->div_clk = clk_get(NULL, id: bgp->conf->div_ck_name); |
920 | if (IS_ERR(ptr: bgp->div_clk)) { |
921 | dev_err(&pdev->dev, "failed to request div_ts_ck clock ref\n" ); |
922 | ret = PTR_ERR(ptr: bgp->div_clk); |
923 | goto put_fclock; |
924 | } |
925 | |
926 | for (i = 0; i < bgp->conf->sensor_count; i++) { |
927 | struct temp_sensor_registers *tsr; |
928 | u32 val; |
929 | |
930 | tsr = bgp->conf->sensors[i].registers; |
931 | /* |
932 | * check if the efuse has a non-zero value if not |
933 | * it is an untrimmed sample and the temperatures |
934 | * may not be accurate |
935 | */ |
936 | val = ti_bandgap_readl(bgp, reg: tsr->bgap_efuse); |
937 | if (!val) |
938 | dev_info(&pdev->dev, |
939 | "Non-trimmed BGAP, Temp not accurate\n" ); |
940 | } |
941 | |
942 | clk_rate = clk_round_rate(clk: bgp->div_clk, |
943 | rate: bgp->conf->sensors[0].ts_data->max_freq); |
944 | if (clk_rate < bgp->conf->sensors[0].ts_data->min_freq || |
945 | clk_rate <= 0) { |
946 | ret = -ENODEV; |
947 | dev_err(&pdev->dev, "wrong clock rate (%d)\n" , clk_rate); |
948 | goto put_clks; |
949 | } |
950 | |
951 | ret = clk_set_rate(clk: bgp->div_clk, rate: clk_rate); |
952 | if (ret) |
953 | dev_err(&pdev->dev, "Cannot re-set clock rate. Continuing\n" ); |
954 | |
955 | bgp->clk_rate = clk_rate; |
956 | if (TI_BANDGAP_HAS(bgp, CLK_CTRL)) |
957 | clk_prepare_enable(clk: bgp->fclock); |
958 | |
959 | |
960 | spin_lock_init(&bgp->lock); |
961 | bgp->dev = &pdev->dev; |
962 | platform_set_drvdata(pdev, data: bgp); |
963 | |
964 | ti_bandgap_power(bgp, on: true); |
965 | |
966 | /* Set default counter to 1 for now */ |
967 | if (TI_BANDGAP_HAS(bgp, COUNTER)) |
968 | for (i = 0; i < bgp->conf->sensor_count; i++) |
969 | RMW_BITS(bgp, i, bgap_counter, counter_mask, 1); |
970 | |
971 | /* Set default thresholds for alert and shutdown */ |
972 | for (i = 0; i < bgp->conf->sensor_count; i++) { |
973 | struct temp_sensor_data *ts_data; |
974 | |
975 | ts_data = bgp->conf->sensors[i].ts_data; |
976 | |
977 | if (TI_BANDGAP_HAS(bgp, TALERT)) { |
978 | /* Set initial Talert thresholds */ |
979 | RMW_BITS(bgp, i, bgap_threshold, |
980 | threshold_tcold_mask, ts_data->t_cold); |
981 | RMW_BITS(bgp, i, bgap_threshold, |
982 | threshold_thot_mask, ts_data->t_hot); |
983 | /* Enable the alert events */ |
984 | RMW_BITS(bgp, i, bgap_mask_ctrl, mask_hot_mask, 1); |
985 | RMW_BITS(bgp, i, bgap_mask_ctrl, mask_cold_mask, 1); |
986 | } |
987 | |
988 | if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG)) { |
989 | /* Set initial Tshut thresholds */ |
990 | RMW_BITS(bgp, i, tshut_threshold, |
991 | tshut_hot_mask, ts_data->tshut_hot); |
992 | RMW_BITS(bgp, i, tshut_threshold, |
993 | tshut_cold_mask, ts_data->tshut_cold); |
994 | } |
995 | } |
996 | |
997 | if (TI_BANDGAP_HAS(bgp, MODE_CONFIG)) |
998 | ti_bandgap_set_continuous_mode(bgp); |
999 | |
1000 | /* Set .250 seconds time as default counter */ |
1001 | if (TI_BANDGAP_HAS(bgp, COUNTER)) |
1002 | for (i = 0; i < bgp->conf->sensor_count; i++) |
1003 | RMW_BITS(bgp, i, bgap_counter, counter_mask, |
1004 | bgp->clk_rate / 4); |
1005 | |
1006 | /* Every thing is good? Then expose the sensors */ |
1007 | for (i = 0; i < bgp->conf->sensor_count; i++) { |
1008 | char *domain; |
1009 | |
1010 | if (bgp->conf->sensors[i].register_cooling) { |
1011 | ret = bgp->conf->sensors[i].register_cooling(bgp, i); |
1012 | if (ret) |
1013 | goto remove_sensors; |
1014 | } |
1015 | |
1016 | if (bgp->conf->expose_sensor) { |
1017 | domain = bgp->conf->sensors[i].domain; |
1018 | ret = bgp->conf->expose_sensor(bgp, i, domain); |
1019 | if (ret) |
1020 | goto remove_last_cooling; |
1021 | } |
1022 | } |
1023 | |
1024 | /* |
1025 | * Enable the Interrupts once everything is set. Otherwise irq handler |
1026 | * might be called as soon as it is enabled where as rest of framework |
1027 | * is still getting initialised. |
1028 | */ |
1029 | if (TI_BANDGAP_HAS(bgp, TALERT)) { |
1030 | ret = ti_bandgap_talert_init(bgp, pdev); |
1031 | if (ret) { |
1032 | dev_err(&pdev->dev, "failed to initialize Talert IRQ\n" ); |
1033 | i = bgp->conf->sensor_count; |
1034 | goto disable_clk; |
1035 | } |
1036 | } |
1037 | |
1038 | #ifdef CONFIG_PM_SLEEP |
1039 | bgp->nb.notifier_call = bandgap_omap_cpu_notifier; |
1040 | if (!soc_device_match(matches: soc_no_cpu_notifier)) |
1041 | cpu_pm_register_notifier(nb: &bgp->nb); |
1042 | #endif |
1043 | |
1044 | return 0; |
1045 | |
1046 | remove_last_cooling: |
1047 | if (bgp->conf->sensors[i].unregister_cooling) |
1048 | bgp->conf->sensors[i].unregister_cooling(bgp, i); |
1049 | remove_sensors: |
1050 | for (i--; i >= 0; i--) { |
1051 | if (bgp->conf->sensors[i].unregister_cooling) |
1052 | bgp->conf->sensors[i].unregister_cooling(bgp, i); |
1053 | if (bgp->conf->remove_sensor) |
1054 | bgp->conf->remove_sensor(bgp, i); |
1055 | } |
1056 | ti_bandgap_power(bgp, on: false); |
1057 | disable_clk: |
1058 | if (TI_BANDGAP_HAS(bgp, CLK_CTRL)) |
1059 | clk_disable_unprepare(clk: bgp->fclock); |
1060 | put_clks: |
1061 | clk_put(clk: bgp->div_clk); |
1062 | put_fclock: |
1063 | clk_put(clk: bgp->fclock); |
1064 | free_irqs: |
1065 | if (TI_BANDGAP_HAS(bgp, TSHUT)) |
1066 | free_irq(gpiod_to_irq(desc: bgp->tshut_gpiod), NULL); |
1067 | |
1068 | return ret; |
1069 | } |
1070 | |
1071 | static |
1072 | void ti_bandgap_remove(struct platform_device *pdev) |
1073 | { |
1074 | struct ti_bandgap *bgp = platform_get_drvdata(pdev); |
1075 | int i; |
1076 | |
1077 | if (!soc_device_match(matches: soc_no_cpu_notifier)) |
1078 | cpu_pm_unregister_notifier(nb: &bgp->nb); |
1079 | |
1080 | /* Remove sensor interfaces */ |
1081 | for (i = 0; i < bgp->conf->sensor_count; i++) { |
1082 | if (bgp->conf->sensors[i].unregister_cooling) |
1083 | bgp->conf->sensors[i].unregister_cooling(bgp, i); |
1084 | |
1085 | if (bgp->conf->remove_sensor) |
1086 | bgp->conf->remove_sensor(bgp, i); |
1087 | } |
1088 | |
1089 | ti_bandgap_power(bgp, on: false); |
1090 | |
1091 | if (TI_BANDGAP_HAS(bgp, CLK_CTRL)) |
1092 | clk_disable_unprepare(clk: bgp->fclock); |
1093 | clk_put(clk: bgp->fclock); |
1094 | clk_put(clk: bgp->div_clk); |
1095 | |
1096 | if (TI_BANDGAP_HAS(bgp, TALERT)) |
1097 | free_irq(bgp->irq, bgp); |
1098 | |
1099 | if (TI_BANDGAP_HAS(bgp, TSHUT)) |
1100 | free_irq(gpiod_to_irq(desc: bgp->tshut_gpiod), NULL); |
1101 | } |
1102 | |
1103 | #ifdef CONFIG_PM_SLEEP |
1104 | static int ti_bandgap_save_ctxt(struct ti_bandgap *bgp) |
1105 | { |
1106 | int i; |
1107 | |
1108 | for (i = 0; i < bgp->conf->sensor_count; i++) { |
1109 | struct temp_sensor_registers *tsr; |
1110 | struct temp_sensor_regval *rval; |
1111 | |
1112 | rval = &bgp->regval[i]; |
1113 | tsr = bgp->conf->sensors[i].registers; |
1114 | |
1115 | if (TI_BANDGAP_HAS(bgp, MODE_CONFIG)) |
1116 | rval->bg_mode_ctrl = ti_bandgap_readl(bgp, |
1117 | reg: tsr->bgap_mode_ctrl); |
1118 | if (TI_BANDGAP_HAS(bgp, COUNTER)) |
1119 | rval->bg_counter = ti_bandgap_readl(bgp, |
1120 | reg: tsr->bgap_counter); |
1121 | if (TI_BANDGAP_HAS(bgp, TALERT)) { |
1122 | rval->bg_threshold = ti_bandgap_readl(bgp, |
1123 | reg: tsr->bgap_threshold); |
1124 | rval->bg_ctrl = ti_bandgap_readl(bgp, |
1125 | reg: tsr->bgap_mask_ctrl); |
1126 | } |
1127 | |
1128 | if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG)) |
1129 | rval->tshut_threshold = ti_bandgap_readl(bgp, |
1130 | reg: tsr->tshut_threshold); |
1131 | } |
1132 | |
1133 | return 0; |
1134 | } |
1135 | |
1136 | static int ti_bandgap_restore_ctxt(struct ti_bandgap *bgp) |
1137 | { |
1138 | int i; |
1139 | |
1140 | for (i = 0; i < bgp->conf->sensor_count; i++) { |
1141 | struct temp_sensor_registers *tsr; |
1142 | struct temp_sensor_regval *rval; |
1143 | |
1144 | rval = &bgp->regval[i]; |
1145 | tsr = bgp->conf->sensors[i].registers; |
1146 | |
1147 | if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG)) |
1148 | ti_bandgap_writel(bgp, val: rval->tshut_threshold, |
1149 | reg: tsr->tshut_threshold); |
1150 | /* Force immediate temperature measurement and update |
1151 | * of the DTEMP field |
1152 | */ |
1153 | ti_bandgap_force_single_read(bgp, id: i); |
1154 | |
1155 | if (TI_BANDGAP_HAS(bgp, COUNTER)) |
1156 | ti_bandgap_writel(bgp, val: rval->bg_counter, |
1157 | reg: tsr->bgap_counter); |
1158 | if (TI_BANDGAP_HAS(bgp, MODE_CONFIG)) |
1159 | ti_bandgap_writel(bgp, val: rval->bg_mode_ctrl, |
1160 | reg: tsr->bgap_mode_ctrl); |
1161 | if (TI_BANDGAP_HAS(bgp, TALERT)) { |
1162 | ti_bandgap_writel(bgp, val: rval->bg_threshold, |
1163 | reg: tsr->bgap_threshold); |
1164 | ti_bandgap_writel(bgp, val: rval->bg_ctrl, |
1165 | reg: tsr->bgap_mask_ctrl); |
1166 | } |
1167 | } |
1168 | |
1169 | return 0; |
1170 | } |
1171 | |
1172 | static int ti_bandgap_suspend(struct device *dev) |
1173 | { |
1174 | struct ti_bandgap *bgp = dev_get_drvdata(dev); |
1175 | int err; |
1176 | |
1177 | err = ti_bandgap_save_ctxt(bgp); |
1178 | ti_bandgap_power(bgp, on: false); |
1179 | |
1180 | if (TI_BANDGAP_HAS(bgp, CLK_CTRL)) |
1181 | clk_disable_unprepare(clk: bgp->fclock); |
1182 | |
1183 | bgp->is_suspended = true; |
1184 | |
1185 | return err; |
1186 | } |
1187 | |
1188 | static int bandgap_omap_cpu_notifier(struct notifier_block *nb, |
1189 | unsigned long cmd, void *v) |
1190 | { |
1191 | struct ti_bandgap *bgp; |
1192 | |
1193 | bgp = container_of(nb, struct ti_bandgap, nb); |
1194 | |
1195 | spin_lock(lock: &bgp->lock); |
1196 | switch (cmd) { |
1197 | case CPU_CLUSTER_PM_ENTER: |
1198 | if (bgp->is_suspended) |
1199 | break; |
1200 | ti_bandgap_save_ctxt(bgp); |
1201 | ti_bandgap_power(bgp, on: false); |
1202 | if (TI_BANDGAP_HAS(bgp, CLK_CTRL)) |
1203 | clk_disable(clk: bgp->fclock); |
1204 | break; |
1205 | case CPU_CLUSTER_PM_ENTER_FAILED: |
1206 | case CPU_CLUSTER_PM_EXIT: |
1207 | if (bgp->is_suspended) |
1208 | break; |
1209 | if (TI_BANDGAP_HAS(bgp, CLK_CTRL)) |
1210 | clk_enable(clk: bgp->fclock); |
1211 | ti_bandgap_power(bgp, on: true); |
1212 | ti_bandgap_restore_ctxt(bgp); |
1213 | break; |
1214 | } |
1215 | spin_unlock(lock: &bgp->lock); |
1216 | |
1217 | return NOTIFY_OK; |
1218 | } |
1219 | |
1220 | static int ti_bandgap_resume(struct device *dev) |
1221 | { |
1222 | struct ti_bandgap *bgp = dev_get_drvdata(dev); |
1223 | |
1224 | if (TI_BANDGAP_HAS(bgp, CLK_CTRL)) |
1225 | clk_prepare_enable(clk: bgp->fclock); |
1226 | |
1227 | ti_bandgap_power(bgp, on: true); |
1228 | bgp->is_suspended = false; |
1229 | |
1230 | return ti_bandgap_restore_ctxt(bgp); |
1231 | } |
1232 | static SIMPLE_DEV_PM_OPS(ti_bandgap_dev_pm_ops, ti_bandgap_suspend, |
1233 | ti_bandgap_resume); |
1234 | |
1235 | #define DEV_PM_OPS (&ti_bandgap_dev_pm_ops) |
1236 | #else |
1237 | #define DEV_PM_OPS NULL |
1238 | #endif |
1239 | |
1240 | static const struct of_device_id of_ti_bandgap_match[] = { |
1241 | #ifdef CONFIG_OMAP3_THERMAL |
1242 | { |
1243 | .compatible = "ti,omap34xx-bandgap" , |
1244 | .data = (void *)&omap34xx_data, |
1245 | }, |
1246 | { |
1247 | .compatible = "ti,omap36xx-bandgap" , |
1248 | .data = (void *)&omap36xx_data, |
1249 | }, |
1250 | #endif |
1251 | #ifdef CONFIG_OMAP4_THERMAL |
1252 | { |
1253 | .compatible = "ti,omap4430-bandgap" , |
1254 | .data = (void *)&omap4430_data, |
1255 | }, |
1256 | { |
1257 | .compatible = "ti,omap4460-bandgap" , |
1258 | .data = (void *)&omap4460_data, |
1259 | }, |
1260 | { |
1261 | .compatible = "ti,omap4470-bandgap" , |
1262 | .data = (void *)&omap4470_data, |
1263 | }, |
1264 | #endif |
1265 | #ifdef CONFIG_OMAP5_THERMAL |
1266 | { |
1267 | .compatible = "ti,omap5430-bandgap" , |
1268 | .data = (void *)&omap5430_data, |
1269 | }, |
1270 | #endif |
1271 | #ifdef CONFIG_DRA752_THERMAL |
1272 | { |
1273 | .compatible = "ti,dra752-bandgap" , |
1274 | .data = (void *)&dra752_data, |
1275 | }, |
1276 | #endif |
1277 | /* Sentinel */ |
1278 | { }, |
1279 | }; |
1280 | MODULE_DEVICE_TABLE(of, of_ti_bandgap_match); |
1281 | |
1282 | static struct platform_driver ti_bandgap_sensor_driver = { |
1283 | .probe = ti_bandgap_probe, |
1284 | .remove_new = ti_bandgap_remove, |
1285 | .driver = { |
1286 | .name = "ti-soc-thermal" , |
1287 | .pm = DEV_PM_OPS, |
1288 | .of_match_table = of_ti_bandgap_match, |
1289 | }, |
1290 | }; |
1291 | |
1292 | module_platform_driver(ti_bandgap_sensor_driver); |
1293 | |
1294 | MODULE_DESCRIPTION("OMAP4+ bandgap temperature sensor driver" ); |
1295 | MODULE_LICENSE("GPL v2" ); |
1296 | MODULE_ALIAS("platform:ti-soc-thermal" ); |
1297 | MODULE_AUTHOR("Texas Instrument Inc." ); |
1298 | |