1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (c) 2020 Linaro Limited |
4 | * |
5 | * Based on original driver: |
6 | * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. |
7 | * |
8 | * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. |
9 | */ |
10 | |
11 | #include <linux/bitfield.h> |
12 | #include <linux/iio/adc/qcom-vadc-common.h> |
13 | #include <linux/iio/consumer.h> |
14 | #include <linux/interrupt.h> |
15 | #include <linux/module.h> |
16 | #include <linux/of.h> |
17 | #include <linux/platform_device.h> |
18 | #include <linux/regmap.h> |
19 | #include <linux/thermal.h> |
20 | |
21 | #include <asm/unaligned.h> |
22 | |
23 | #include "../thermal_hwmon.h" |
24 | |
25 | /* |
26 | * Thermal monitoring block consists of 8 (ADC_TM5_NUM_CHANNELS) channels. Each |
27 | * channel is programmed to use one of ADC channels for voltage comparison. |
28 | * Voltages are programmed using ADC codes, so we have to convert temp to |
29 | * voltage and then to ADC code value. |
30 | * |
31 | * Configuration of TM channels must match configuration of corresponding ADC |
32 | * channels. |
33 | */ |
34 | |
35 | #define ADC5_MAX_CHANNEL 0xc0 |
36 | #define ADC_TM5_NUM_CHANNELS 8 |
37 | |
38 | #define ADC_TM5_STATUS_LOW 0x0a |
39 | |
40 | #define ADC_TM5_STATUS_HIGH 0x0b |
41 | |
42 | #define ADC_TM5_NUM_BTM 0x0f |
43 | |
44 | #define ADC_TM5_ADC_DIG_PARAM 0x42 |
45 | |
46 | #define ADC_TM5_FAST_AVG_CTL (ADC_TM5_ADC_DIG_PARAM + 1) |
47 | #define ADC_TM5_FAST_AVG_EN BIT(7) |
48 | |
49 | #define ADC_TM5_MEAS_INTERVAL_CTL (ADC_TM5_ADC_DIG_PARAM + 2) |
50 | #define ADC_TM5_TIMER1 3 /* 3.9ms */ |
51 | |
52 | #define ADC_TM5_MEAS_INTERVAL_CTL2 (ADC_TM5_ADC_DIG_PARAM + 3) |
53 | #define ADC_TM5_MEAS_INTERVAL_CTL2_MASK 0xf0 |
54 | #define ADC_TM5_TIMER2 10 /* 1 second */ |
55 | #define ADC_TM5_MEAS_INTERVAL_CTL3_MASK 0xf |
56 | #define ADC_TM5_TIMER3 4 /* 4 second */ |
57 | |
58 | #define ADC_TM_EN_CTL1 0x46 |
59 | #define ADC_TM_EN BIT(7) |
60 | #define ADC_TM_CONV_REQ 0x47 |
61 | #define ADC_TM_CONV_REQ_EN BIT(7) |
62 | |
63 | #define ADC_TM5_M_CHAN_BASE 0x60 |
64 | |
65 | #define ADC_TM5_M_ADC_CH_SEL_CTL(n) (ADC_TM5_M_CHAN_BASE + ((n) * 8) + 0) |
66 | #define ADC_TM5_M_LOW_THR0(n) (ADC_TM5_M_CHAN_BASE + ((n) * 8) + 1) |
67 | #define ADC_TM5_M_LOW_THR1(n) (ADC_TM5_M_CHAN_BASE + ((n) * 8) + 2) |
68 | #define ADC_TM5_M_HIGH_THR0(n) (ADC_TM5_M_CHAN_BASE + ((n) * 8) + 3) |
69 | #define ADC_TM5_M_HIGH_THR1(n) (ADC_TM5_M_CHAN_BASE + ((n) * 8) + 4) |
70 | #define ADC_TM5_M_MEAS_INTERVAL_CTL(n) (ADC_TM5_M_CHAN_BASE + ((n) * 8) + 5) |
71 | #define ADC_TM5_M_CTL(n) (ADC_TM5_M_CHAN_BASE + ((n) * 8) + 6) |
72 | #define ADC_TM5_M_CTL_HW_SETTLE_DELAY_MASK 0xf |
73 | #define ADC_TM5_M_CTL_CAL_SEL_MASK 0x30 |
74 | #define ADC_TM5_M_CTL_CAL_VAL 0x40 |
75 | #define ADC_TM5_M_EN(n) (ADC_TM5_M_CHAN_BASE + ((n) * 8) + 7) |
76 | #define ADC_TM5_M_MEAS_EN BIT(7) |
77 | #define ADC_TM5_M_HIGH_THR_INT_EN BIT(1) |
78 | #define ADC_TM5_M_LOW_THR_INT_EN BIT(0) |
79 | |
80 | #define ADC_TM_GEN2_STATUS1 0x08 |
81 | #define ADC_TM_GEN2_STATUS_LOW_SET 0x09 |
82 | #define ADC_TM_GEN2_STATUS_LOW_CLR 0x0a |
83 | #define ADC_TM_GEN2_STATUS_HIGH_SET 0x0b |
84 | #define ADC_TM_GEN2_STATUS_HIGH_CLR 0x0c |
85 | |
86 | #define ADC_TM_GEN2_CFG_HS_SET 0x0d |
87 | #define ADC_TM_GEN2_CFG_HS_FLAG BIT(0) |
88 | #define ADC_TM_GEN2_CFG_HS_CLR 0x0e |
89 | |
90 | #define ADC_TM_GEN2_SID 0x40 |
91 | |
92 | #define ADC_TM_GEN2_CH_CTL 0x41 |
93 | #define ADC_TM_GEN2_TM_CH_SEL GENMASK(7, 5) |
94 | #define ADC_TM_GEN2_MEAS_INT_SEL GENMASK(3, 2) |
95 | |
96 | #define ADC_TM_GEN2_ADC_DIG_PARAM 0x42 |
97 | #define ADC_TM_GEN2_CTL_CAL_SEL GENMASK(5, 4) |
98 | #define ADC_TM_GEN2_CTL_DEC_RATIO_MASK GENMASK(3, 2) |
99 | |
100 | #define ADC_TM_GEN2_FAST_AVG_CTL 0x43 |
101 | #define ADC_TM_GEN2_FAST_AVG_EN BIT(7) |
102 | |
103 | #define ADC_TM_GEN2_ADC_CH_SEL_CTL 0x44 |
104 | |
105 | #define ADC_TM_GEN2_DELAY_CTL 0x45 |
106 | #define ADC_TM_GEN2_HW_SETTLE_DELAY GENMASK(3, 0) |
107 | |
108 | #define ADC_TM_GEN2_EN_CTL1 0x46 |
109 | #define ADC_TM_GEN2_EN BIT(7) |
110 | |
111 | #define ADC_TM_GEN2_CONV_REQ 0x47 |
112 | #define ADC_TM_GEN2_CONV_REQ_EN BIT(7) |
113 | |
114 | #define ADC_TM_GEN2_LOW_THR0 0x49 |
115 | #define ADC_TM_GEN2_LOW_THR1 0x4a |
116 | #define ADC_TM_GEN2_HIGH_THR0 0x4b |
117 | #define ADC_TM_GEN2_HIGH_THR1 0x4c |
118 | #define ADC_TM_GEN2_LOWER_MASK(n) ((n) & GENMASK(7, 0)) |
119 | #define ADC_TM_GEN2_UPPER_MASK(n) (((n) & GENMASK(15, 8)) >> 8) |
120 | |
121 | #define ADC_TM_GEN2_MEAS_IRQ_EN 0x4d |
122 | #define ADC_TM_GEN2_MEAS_EN BIT(7) |
123 | #define ADC_TM5_GEN2_HIGH_THR_INT_EN BIT(1) |
124 | #define ADC_TM5_GEN2_LOW_THR_INT_EN BIT(0) |
125 | |
126 | #define ADC_TM_GEN2_MEAS_INT_LSB 0x50 |
127 | #define ADC_TM_GEN2_MEAS_INT_MSB 0x51 |
128 | #define ADC_TM_GEN2_MEAS_INT_MODE 0x52 |
129 | |
130 | #define ADC_TM_GEN2_Mn_DATA0(n) ((n * 2) + 0xa0) |
131 | #define ADC_TM_GEN2_Mn_DATA1(n) ((n * 2) + 0xa1) |
132 | #define ADC_TM_GEN2_DATA_SHIFT 8 |
133 | |
134 | enum adc5_timer_select { |
135 | ADC5_TIMER_SEL_1 = 0, |
136 | ADC5_TIMER_SEL_2, |
137 | ADC5_TIMER_SEL_3, |
138 | ADC5_TIMER_SEL_NONE, |
139 | }; |
140 | |
141 | enum adc5_gen { |
142 | ADC_TM5, |
143 | ADC_TM_HC, |
144 | ADC_TM5_GEN2, |
145 | ADC_TM5_MAX |
146 | }; |
147 | |
148 | enum adc_tm5_cal_method { |
149 | ADC_TM5_NO_CAL = 0, |
150 | ADC_TM5_RATIOMETRIC_CAL, |
151 | ADC_TM5_ABSOLUTE_CAL |
152 | }; |
153 | |
154 | enum adc_tm_gen2_time_select { |
155 | MEAS_INT_50MS = 0, |
156 | MEAS_INT_100MS, |
157 | MEAS_INT_1S, |
158 | MEAS_INT_SET, |
159 | MEAS_INT_NONE, |
160 | }; |
161 | |
162 | struct adc_tm5_chip; |
163 | struct adc_tm5_channel; |
164 | |
165 | struct adc_tm5_data { |
166 | const u32 full_scale_code_volt; |
167 | unsigned int *decimation; |
168 | unsigned int *hw_settle; |
169 | int (*disable_channel)(struct adc_tm5_channel *channel); |
170 | int (*configure)(struct adc_tm5_channel *channel, int low, int high); |
171 | irqreturn_t (*isr)(int irq, void *data); |
172 | int (*init)(struct adc_tm5_chip *chip); |
173 | char *irq_name; |
174 | int gen; |
175 | }; |
176 | |
177 | /** |
178 | * struct adc_tm5_channel - ADC Thermal Monitoring channel data. |
179 | * @channel: channel number. |
180 | * @adc_channel: corresponding ADC channel number. |
181 | * @cal_method: calibration method. |
182 | * @prescale: channel scaling performed on the input signal. |
183 | * @hw_settle_time: the time between AMUX being configured and the |
184 | * start of conversion. |
185 | * @decimation: sampling rate supported for the channel. |
186 | * @avg_samples: ability to provide single result from the ADC |
187 | * that is an average of multiple measurements. |
188 | * @high_thr_en: channel upper voltage threshold enable state. |
189 | * @low_thr_en: channel lower voltage threshold enable state. |
190 | * @meas_en: recurring measurement enable state |
191 | * @iio: IIO channel instance used by this channel. |
192 | * @chip: ADC TM chip instance. |
193 | * @tzd: thermal zone device used by this channel. |
194 | */ |
195 | struct adc_tm5_channel { |
196 | unsigned int channel; |
197 | unsigned int adc_channel; |
198 | enum adc_tm5_cal_method cal_method; |
199 | unsigned int prescale; |
200 | unsigned int hw_settle_time; |
201 | unsigned int decimation; /* For Gen2 ADC_TM */ |
202 | unsigned int avg_samples; /* For Gen2 ADC_TM */ |
203 | bool high_thr_en; /* For Gen2 ADC_TM */ |
204 | bool low_thr_en; /* For Gen2 ADC_TM */ |
205 | bool meas_en; /* For Gen2 ADC_TM */ |
206 | struct iio_channel *iio; |
207 | struct adc_tm5_chip *chip; |
208 | struct thermal_zone_device *tzd; |
209 | }; |
210 | |
211 | /** |
212 | * struct adc_tm5_chip - ADC Thermal Monitoring properties |
213 | * @regmap: SPMI ADC5 Thermal Monitoring peripheral register map field. |
214 | * @dev: SPMI ADC5 device. |
215 | * @data: software configuration data. |
216 | * @channels: array of ADC TM channel data. |
217 | * @nchannels: amount of channels defined/allocated |
218 | * @decimation: sampling rate supported for the channel. |
219 | * Applies to all channels, used only on Gen1 ADC_TM. |
220 | * @avg_samples: ability to provide single result from the ADC |
221 | * that is an average of multiple measurements. Applies to all |
222 | * channels, used only on Gen1 ADC_TM. |
223 | * @base: base address of TM registers. |
224 | * @adc_mutex_lock: ADC_TM mutex lock, used only on Gen2 ADC_TM. |
225 | * It is used to ensure only one ADC channel configuration |
226 | * is done at a time using the shared set of configuration |
227 | * registers. |
228 | */ |
229 | struct adc_tm5_chip { |
230 | struct regmap *regmap; |
231 | struct device *dev; |
232 | const struct adc_tm5_data *data; |
233 | struct adc_tm5_channel *channels; |
234 | unsigned int nchannels; |
235 | unsigned int decimation; |
236 | unsigned int avg_samples; |
237 | u16 base; |
238 | struct mutex adc_mutex_lock; |
239 | }; |
240 | |
241 | static int adc_tm5_read(struct adc_tm5_chip *adc_tm, u16 offset, u8 *data, int len) |
242 | { |
243 | return regmap_bulk_read(map: adc_tm->regmap, reg: adc_tm->base + offset, val: data, val_count: len); |
244 | } |
245 | |
246 | static int adc_tm5_write(struct adc_tm5_chip *adc_tm, u16 offset, u8 *data, int len) |
247 | { |
248 | return regmap_bulk_write(map: adc_tm->regmap, reg: adc_tm->base + offset, val: data, val_count: len); |
249 | } |
250 | |
251 | static int adc_tm5_reg_update(struct adc_tm5_chip *adc_tm, u16 offset, u8 mask, u8 val) |
252 | { |
253 | return regmap_write_bits(map: adc_tm->regmap, reg: adc_tm->base + offset, mask, val); |
254 | } |
255 | |
256 | static irqreturn_t adc_tm5_isr(int irq, void *data) |
257 | { |
258 | struct adc_tm5_chip *chip = data; |
259 | u8 status_low, status_high, ctl; |
260 | int ret, i; |
261 | |
262 | ret = adc_tm5_read(adc_tm: chip, ADC_TM5_STATUS_LOW, data: &status_low, len: sizeof(status_low)); |
263 | if (unlikely(ret)) { |
264 | dev_err(chip->dev, "read status low failed: %d\n" , ret); |
265 | return IRQ_HANDLED; |
266 | } |
267 | |
268 | ret = adc_tm5_read(adc_tm: chip, ADC_TM5_STATUS_HIGH, data: &status_high, len: sizeof(status_high)); |
269 | if (unlikely(ret)) { |
270 | dev_err(chip->dev, "read status high failed: %d\n" , ret); |
271 | return IRQ_HANDLED; |
272 | } |
273 | |
274 | for (i = 0; i < chip->nchannels; i++) { |
275 | bool upper_set = false, lower_set = false; |
276 | unsigned int ch = chip->channels[i].channel; |
277 | |
278 | /* No TZD, we warned at the boot time */ |
279 | if (!chip->channels[i].tzd) |
280 | continue; |
281 | |
282 | ret = adc_tm5_read(adc_tm: chip, ADC_TM5_M_EN(ch), data: &ctl, len: sizeof(ctl)); |
283 | if (unlikely(ret)) { |
284 | dev_err(chip->dev, "ctl read failed: %d, channel %d\n" , ret, i); |
285 | continue; |
286 | } |
287 | |
288 | if (!(ctl & ADC_TM5_M_MEAS_EN)) |
289 | continue; |
290 | |
291 | lower_set = (status_low & BIT(ch)) && |
292 | (ctl & ADC_TM5_M_LOW_THR_INT_EN); |
293 | |
294 | upper_set = (status_high & BIT(ch)) && |
295 | (ctl & ADC_TM5_M_HIGH_THR_INT_EN); |
296 | |
297 | if (upper_set || lower_set) |
298 | thermal_zone_device_update(chip->channels[i].tzd, |
299 | THERMAL_EVENT_UNSPECIFIED); |
300 | } |
301 | |
302 | return IRQ_HANDLED; |
303 | } |
304 | |
305 | static irqreturn_t adc_tm5_gen2_isr(int irq, void *data) |
306 | { |
307 | struct adc_tm5_chip *chip = data; |
308 | u8 status_low, status_high; |
309 | int ret, i; |
310 | |
311 | ret = adc_tm5_read(adc_tm: chip, ADC_TM_GEN2_STATUS_LOW_CLR, data: &status_low, len: sizeof(status_low)); |
312 | if (ret) { |
313 | dev_err(chip->dev, "read status_low failed: %d\n" , ret); |
314 | return IRQ_HANDLED; |
315 | } |
316 | |
317 | ret = adc_tm5_read(adc_tm: chip, ADC_TM_GEN2_STATUS_HIGH_CLR, data: &status_high, len: sizeof(status_high)); |
318 | if (ret) { |
319 | dev_err(chip->dev, "read status_high failed: %d\n" , ret); |
320 | return IRQ_HANDLED; |
321 | } |
322 | |
323 | ret = adc_tm5_write(adc_tm: chip, ADC_TM_GEN2_STATUS_LOW_CLR, data: &status_low, len: sizeof(status_low)); |
324 | if (ret < 0) { |
325 | dev_err(chip->dev, "clear status low failed with %d\n" , ret); |
326 | return IRQ_HANDLED; |
327 | } |
328 | |
329 | ret = adc_tm5_write(adc_tm: chip, ADC_TM_GEN2_STATUS_HIGH_CLR, data: &status_high, len: sizeof(status_high)); |
330 | if (ret < 0) { |
331 | dev_err(chip->dev, "clear status high failed with %d\n" , ret); |
332 | return IRQ_HANDLED; |
333 | } |
334 | |
335 | for (i = 0; i < chip->nchannels; i++) { |
336 | bool upper_set = false, lower_set = false; |
337 | unsigned int ch = chip->channels[i].channel; |
338 | |
339 | /* No TZD, we warned at the boot time */ |
340 | if (!chip->channels[i].tzd) |
341 | continue; |
342 | |
343 | if (!chip->channels[i].meas_en) |
344 | continue; |
345 | |
346 | lower_set = (status_low & BIT(ch)) && |
347 | (chip->channels[i].low_thr_en); |
348 | |
349 | upper_set = (status_high & BIT(ch)) && |
350 | (chip->channels[i].high_thr_en); |
351 | |
352 | if (upper_set || lower_set) |
353 | thermal_zone_device_update(chip->channels[i].tzd, |
354 | THERMAL_EVENT_UNSPECIFIED); |
355 | } |
356 | |
357 | return IRQ_HANDLED; |
358 | } |
359 | |
360 | static int adc_tm5_get_temp(struct thermal_zone_device *tz, int *temp) |
361 | { |
362 | struct adc_tm5_channel *channel = thermal_zone_device_priv(tzd: tz); |
363 | int ret; |
364 | |
365 | if (!channel || !channel->iio) |
366 | return -EINVAL; |
367 | |
368 | ret = iio_read_channel_processed(chan: channel->iio, val: temp); |
369 | if (ret < 0) |
370 | return ret; |
371 | |
372 | if (ret != IIO_VAL_INT) |
373 | return -EINVAL; |
374 | |
375 | return 0; |
376 | } |
377 | |
378 | static int adc_tm5_disable_channel(struct adc_tm5_channel *channel) |
379 | { |
380 | struct adc_tm5_chip *chip = channel->chip; |
381 | unsigned int reg = ADC_TM5_M_EN(channel->channel); |
382 | |
383 | return adc_tm5_reg_update(adc_tm: chip, offset: reg, |
384 | ADC_TM5_M_MEAS_EN | |
385 | ADC_TM5_M_HIGH_THR_INT_EN | |
386 | ADC_TM5_M_LOW_THR_INT_EN, |
387 | val: 0); |
388 | } |
389 | |
390 | #define ADC_TM_GEN2_POLL_DELAY_MIN_US 100 |
391 | #define ADC_TM_GEN2_POLL_DELAY_MAX_US 110 |
392 | #define ADC_TM_GEN2_POLL_RETRY_COUNT 3 |
393 | |
394 | static int32_t adc_tm5_gen2_conv_req(struct adc_tm5_chip *chip) |
395 | { |
396 | int ret; |
397 | u8 data; |
398 | unsigned int count; |
399 | |
400 | data = ADC_TM_GEN2_EN; |
401 | ret = adc_tm5_write(adc_tm: chip, ADC_TM_GEN2_EN_CTL1, data: &data, len: 1); |
402 | if (ret < 0) { |
403 | dev_err(chip->dev, "adc-tm enable failed with %d\n" , ret); |
404 | return ret; |
405 | } |
406 | |
407 | data = ADC_TM_GEN2_CFG_HS_FLAG; |
408 | ret = adc_tm5_write(adc_tm: chip, ADC_TM_GEN2_CFG_HS_SET, data: &data, len: 1); |
409 | if (ret < 0) { |
410 | dev_err(chip->dev, "adc-tm handshake failed with %d\n" , ret); |
411 | return ret; |
412 | } |
413 | |
414 | data = ADC_TM_GEN2_CONV_REQ_EN; |
415 | ret = adc_tm5_write(adc_tm: chip, ADC_TM_GEN2_CONV_REQ, data: &data, len: 1); |
416 | if (ret < 0) { |
417 | dev_err(chip->dev, "adc-tm request conversion failed with %d\n" , ret); |
418 | return ret; |
419 | } |
420 | |
421 | /* |
422 | * SW sets a handshake bit and waits for PBS to clear it |
423 | * before the next conversion request can be queued. |
424 | */ |
425 | |
426 | for (count = 0; count < ADC_TM_GEN2_POLL_RETRY_COUNT; count++) { |
427 | ret = adc_tm5_read(adc_tm: chip, ADC_TM_GEN2_CFG_HS_SET, data: &data, len: sizeof(data)); |
428 | if (ret < 0) { |
429 | dev_err(chip->dev, "adc-tm read failed with %d\n" , ret); |
430 | return ret; |
431 | } |
432 | |
433 | if (!(data & ADC_TM_GEN2_CFG_HS_FLAG)) |
434 | return ret; |
435 | usleep_range(ADC_TM_GEN2_POLL_DELAY_MIN_US, |
436 | ADC_TM_GEN2_POLL_DELAY_MAX_US); |
437 | } |
438 | |
439 | dev_err(chip->dev, "adc-tm conversion request handshake timed out\n" ); |
440 | |
441 | return -ETIMEDOUT; |
442 | } |
443 | |
444 | static int adc_tm5_gen2_disable_channel(struct adc_tm5_channel *channel) |
445 | { |
446 | struct adc_tm5_chip *chip = channel->chip; |
447 | int ret; |
448 | u8 val; |
449 | |
450 | mutex_lock(&chip->adc_mutex_lock); |
451 | |
452 | channel->meas_en = false; |
453 | channel->high_thr_en = false; |
454 | channel->low_thr_en = false; |
455 | |
456 | ret = adc_tm5_read(adc_tm: chip, ADC_TM_GEN2_CH_CTL, data: &val, len: sizeof(val)); |
457 | if (ret < 0) { |
458 | dev_err(chip->dev, "adc-tm block read failed with %d\n" , ret); |
459 | goto disable_fail; |
460 | } |
461 | |
462 | val &= ~ADC_TM_GEN2_TM_CH_SEL; |
463 | val |= FIELD_PREP(ADC_TM_GEN2_TM_CH_SEL, channel->channel); |
464 | |
465 | ret = adc_tm5_write(adc_tm: chip, ADC_TM_GEN2_CH_CTL, data: &val, len: 1); |
466 | if (ret < 0) { |
467 | dev_err(chip->dev, "adc-tm channel disable failed with %d\n" , ret); |
468 | goto disable_fail; |
469 | } |
470 | |
471 | val = 0; |
472 | ret = adc_tm5_write(adc_tm: chip, ADC_TM_GEN2_MEAS_IRQ_EN, data: &val, len: 1); |
473 | if (ret < 0) { |
474 | dev_err(chip->dev, "adc-tm interrupt disable failed with %d\n" , ret); |
475 | goto disable_fail; |
476 | } |
477 | |
478 | |
479 | ret = adc_tm5_gen2_conv_req(chip: channel->chip); |
480 | if (ret < 0) |
481 | dev_err(chip->dev, "adc-tm channel configure failed with %d\n" , ret); |
482 | |
483 | disable_fail: |
484 | mutex_unlock(lock: &chip->adc_mutex_lock); |
485 | return ret; |
486 | } |
487 | |
488 | static int adc_tm5_enable(struct adc_tm5_chip *chip) |
489 | { |
490 | int ret; |
491 | u8 data; |
492 | |
493 | data = ADC_TM_EN; |
494 | ret = adc_tm5_write(adc_tm: chip, ADC_TM_EN_CTL1, data: &data, len: sizeof(data)); |
495 | if (ret < 0) { |
496 | dev_err(chip->dev, "adc-tm enable failed\n" ); |
497 | return ret; |
498 | } |
499 | |
500 | data = ADC_TM_CONV_REQ_EN; |
501 | ret = adc_tm5_write(adc_tm: chip, ADC_TM_CONV_REQ, data: &data, len: sizeof(data)); |
502 | if (ret < 0) { |
503 | dev_err(chip->dev, "adc-tm request conversion failed\n" ); |
504 | return ret; |
505 | } |
506 | |
507 | return 0; |
508 | } |
509 | |
510 | static int adc_tm5_configure(struct adc_tm5_channel *channel, int low, int high) |
511 | { |
512 | struct adc_tm5_chip *chip = channel->chip; |
513 | u8 buf[8]; |
514 | u16 reg = ADC_TM5_M_ADC_CH_SEL_CTL(channel->channel); |
515 | int ret; |
516 | |
517 | ret = adc_tm5_read(adc_tm: chip, offset: reg, data: buf, len: sizeof(buf)); |
518 | if (ret) { |
519 | dev_err(chip->dev, "channel %d params read failed: %d\n" , channel->channel, ret); |
520 | return ret; |
521 | } |
522 | |
523 | buf[0] = channel->adc_channel; |
524 | |
525 | /* High temperature corresponds to low voltage threshold */ |
526 | if (high != INT_MAX) { |
527 | u16 adc_code = qcom_adc_tm5_temp_volt_scale(prescale_ratio: channel->prescale, |
528 | full_scale_code_volt: chip->data->full_scale_code_volt, temp: high); |
529 | |
530 | put_unaligned_le16(val: adc_code, p: &buf[1]); |
531 | buf[7] |= ADC_TM5_M_LOW_THR_INT_EN; |
532 | } else { |
533 | buf[7] &= ~ADC_TM5_M_LOW_THR_INT_EN; |
534 | } |
535 | |
536 | /* Low temperature corresponds to high voltage threshold */ |
537 | if (low != -INT_MAX) { |
538 | u16 adc_code = qcom_adc_tm5_temp_volt_scale(prescale_ratio: channel->prescale, |
539 | full_scale_code_volt: chip->data->full_scale_code_volt, temp: low); |
540 | |
541 | put_unaligned_le16(val: adc_code, p: &buf[3]); |
542 | buf[7] |= ADC_TM5_M_HIGH_THR_INT_EN; |
543 | } else { |
544 | buf[7] &= ~ADC_TM5_M_HIGH_THR_INT_EN; |
545 | } |
546 | |
547 | buf[5] = ADC5_TIMER_SEL_2; |
548 | |
549 | /* Set calibration select, hw_settle delay */ |
550 | buf[6] &= ~ADC_TM5_M_CTL_HW_SETTLE_DELAY_MASK; |
551 | buf[6] |= FIELD_PREP(ADC_TM5_M_CTL_HW_SETTLE_DELAY_MASK, channel->hw_settle_time); |
552 | buf[6] &= ~ADC_TM5_M_CTL_CAL_SEL_MASK; |
553 | buf[6] |= FIELD_PREP(ADC_TM5_M_CTL_CAL_SEL_MASK, channel->cal_method); |
554 | |
555 | buf[7] |= ADC_TM5_M_MEAS_EN; |
556 | |
557 | ret = adc_tm5_write(adc_tm: chip, offset: reg, data: buf, len: sizeof(buf)); |
558 | if (ret) { |
559 | dev_err(chip->dev, "channel %d params write failed: %d\n" , channel->channel, ret); |
560 | return ret; |
561 | } |
562 | |
563 | return adc_tm5_enable(chip); |
564 | } |
565 | |
566 | static int adc_tm5_gen2_configure(struct adc_tm5_channel *channel, int low, int high) |
567 | { |
568 | struct adc_tm5_chip *chip = channel->chip; |
569 | int ret; |
570 | u8 buf[14]; |
571 | u16 adc_code; |
572 | |
573 | mutex_lock(&chip->adc_mutex_lock); |
574 | |
575 | channel->meas_en = true; |
576 | |
577 | ret = adc_tm5_read(adc_tm: chip, ADC_TM_GEN2_SID, data: buf, len: sizeof(buf)); |
578 | if (ret < 0) { |
579 | dev_err(chip->dev, "adc-tm block read failed with %d\n" , ret); |
580 | goto config_fail; |
581 | } |
582 | |
583 | /* Set SID from virtual channel number */ |
584 | buf[0] = channel->adc_channel >> 8; |
585 | |
586 | /* Set TM channel number used and measurement interval */ |
587 | buf[1] &= ~ADC_TM_GEN2_TM_CH_SEL; |
588 | buf[1] |= FIELD_PREP(ADC_TM_GEN2_TM_CH_SEL, channel->channel); |
589 | buf[1] &= ~ADC_TM_GEN2_MEAS_INT_SEL; |
590 | buf[1] |= FIELD_PREP(ADC_TM_GEN2_MEAS_INT_SEL, MEAS_INT_1S); |
591 | |
592 | buf[2] &= ~ADC_TM_GEN2_CTL_DEC_RATIO_MASK; |
593 | buf[2] |= FIELD_PREP(ADC_TM_GEN2_CTL_DEC_RATIO_MASK, channel->decimation); |
594 | buf[2] &= ~ADC_TM_GEN2_CTL_CAL_SEL; |
595 | buf[2] |= FIELD_PREP(ADC_TM_GEN2_CTL_CAL_SEL, channel->cal_method); |
596 | |
597 | buf[3] = channel->avg_samples | ADC_TM_GEN2_FAST_AVG_EN; |
598 | |
599 | buf[4] = channel->adc_channel & 0xff; |
600 | |
601 | buf[5] = channel->hw_settle_time & ADC_TM_GEN2_HW_SETTLE_DELAY; |
602 | |
603 | /* High temperature corresponds to low voltage threshold */ |
604 | if (high != INT_MAX) { |
605 | channel->low_thr_en = true; |
606 | adc_code = qcom_adc_tm5_gen2_temp_res_scale(temp: high); |
607 | put_unaligned_le16(val: adc_code, p: &buf[9]); |
608 | } else { |
609 | channel->low_thr_en = false; |
610 | } |
611 | |
612 | /* Low temperature corresponds to high voltage threshold */ |
613 | if (low != -INT_MAX) { |
614 | channel->high_thr_en = true; |
615 | adc_code = qcom_adc_tm5_gen2_temp_res_scale(temp: low); |
616 | put_unaligned_le16(val: adc_code, p: &buf[11]); |
617 | } else { |
618 | channel->high_thr_en = false; |
619 | } |
620 | |
621 | buf[13] = ADC_TM_GEN2_MEAS_EN; |
622 | if (channel->high_thr_en) |
623 | buf[13] |= ADC_TM5_GEN2_HIGH_THR_INT_EN; |
624 | if (channel->low_thr_en) |
625 | buf[13] |= ADC_TM5_GEN2_LOW_THR_INT_EN; |
626 | |
627 | ret = adc_tm5_write(adc_tm: chip, ADC_TM_GEN2_SID, data: buf, len: sizeof(buf)); |
628 | if (ret) { |
629 | dev_err(chip->dev, "channel %d params write failed: %d\n" , channel->channel, ret); |
630 | goto config_fail; |
631 | } |
632 | |
633 | ret = adc_tm5_gen2_conv_req(chip: channel->chip); |
634 | if (ret < 0) |
635 | dev_err(chip->dev, "adc-tm channel configure failed with %d\n" , ret); |
636 | |
637 | config_fail: |
638 | mutex_unlock(lock: &chip->adc_mutex_lock); |
639 | return ret; |
640 | } |
641 | |
642 | static int adc_tm5_set_trips(struct thermal_zone_device *tz, int low, int high) |
643 | { |
644 | struct adc_tm5_channel *channel = thermal_zone_device_priv(tzd: tz); |
645 | struct adc_tm5_chip *chip; |
646 | int ret; |
647 | |
648 | if (!channel) |
649 | return -EINVAL; |
650 | |
651 | chip = channel->chip; |
652 | dev_dbg(chip->dev, "%d:low(mdegC):%d, high(mdegC):%d\n" , |
653 | channel->channel, low, high); |
654 | |
655 | if (high == INT_MAX && low <= -INT_MAX) |
656 | ret = chip->data->disable_channel(channel); |
657 | else |
658 | ret = chip->data->configure(channel, low, high); |
659 | |
660 | return ret; |
661 | } |
662 | |
663 | static const struct thermal_zone_device_ops adc_tm5_thermal_ops = { |
664 | .get_temp = adc_tm5_get_temp, |
665 | .set_trips = adc_tm5_set_trips, |
666 | }; |
667 | |
668 | static int adc_tm5_register_tzd(struct adc_tm5_chip *adc_tm) |
669 | { |
670 | unsigned int i; |
671 | struct thermal_zone_device *tzd; |
672 | |
673 | for (i = 0; i < adc_tm->nchannels; i++) { |
674 | adc_tm->channels[i].chip = adc_tm; |
675 | tzd = devm_thermal_of_zone_register(dev: adc_tm->dev, |
676 | id: adc_tm->channels[i].channel, |
677 | data: &adc_tm->channels[i], |
678 | ops: &adc_tm5_thermal_ops); |
679 | if (IS_ERR(ptr: tzd)) { |
680 | if (PTR_ERR(ptr: tzd) == -ENODEV) { |
681 | dev_dbg(adc_tm->dev, "thermal sensor on channel %d is not used\n" , |
682 | adc_tm->channels[i].channel); |
683 | continue; |
684 | } |
685 | |
686 | dev_err(adc_tm->dev, "Error registering TZ zone for channel %d: %ld\n" , |
687 | adc_tm->channels[i].channel, PTR_ERR(tzd)); |
688 | return PTR_ERR(ptr: tzd); |
689 | } |
690 | adc_tm->channels[i].tzd = tzd; |
691 | devm_thermal_add_hwmon_sysfs(dev: adc_tm->dev, tz: tzd); |
692 | } |
693 | |
694 | return 0; |
695 | } |
696 | |
697 | static int adc_tm_hc_init(struct adc_tm5_chip *chip) |
698 | { |
699 | unsigned int i; |
700 | u8 buf[2]; |
701 | int ret; |
702 | |
703 | for (i = 0; i < chip->nchannels; i++) { |
704 | if (chip->channels[i].channel >= ADC_TM5_NUM_CHANNELS) { |
705 | dev_err(chip->dev, "Invalid channel %d\n" , chip->channels[i].channel); |
706 | return -EINVAL; |
707 | } |
708 | } |
709 | |
710 | buf[0] = chip->decimation; |
711 | buf[1] = chip->avg_samples | ADC_TM5_FAST_AVG_EN; |
712 | |
713 | ret = adc_tm5_write(adc_tm: chip, ADC_TM5_ADC_DIG_PARAM, data: buf, len: sizeof(buf)); |
714 | if (ret) |
715 | dev_err(chip->dev, "block write failed: %d\n" , ret); |
716 | |
717 | return ret; |
718 | } |
719 | |
720 | static int adc_tm5_init(struct adc_tm5_chip *chip) |
721 | { |
722 | u8 buf[4], channels_available; |
723 | int ret; |
724 | unsigned int i; |
725 | |
726 | ret = adc_tm5_read(adc_tm: chip, ADC_TM5_NUM_BTM, |
727 | data: &channels_available, len: sizeof(channels_available)); |
728 | if (ret) { |
729 | dev_err(chip->dev, "read failed for BTM channels\n" ); |
730 | return ret; |
731 | } |
732 | |
733 | for (i = 0; i < chip->nchannels; i++) { |
734 | if (chip->channels[i].channel >= channels_available) { |
735 | dev_err(chip->dev, "Invalid channel %d\n" , chip->channels[i].channel); |
736 | return -EINVAL; |
737 | } |
738 | } |
739 | |
740 | buf[0] = chip->decimation; |
741 | buf[1] = chip->avg_samples | ADC_TM5_FAST_AVG_EN; |
742 | buf[2] = ADC_TM5_TIMER1; |
743 | buf[3] = FIELD_PREP(ADC_TM5_MEAS_INTERVAL_CTL2_MASK, ADC_TM5_TIMER2) | |
744 | FIELD_PREP(ADC_TM5_MEAS_INTERVAL_CTL3_MASK, ADC_TM5_TIMER3); |
745 | |
746 | ret = adc_tm5_write(adc_tm: chip, ADC_TM5_ADC_DIG_PARAM, data: buf, len: sizeof(buf)); |
747 | if (ret) { |
748 | dev_err(chip->dev, "block write failed: %d\n" , ret); |
749 | return ret; |
750 | } |
751 | |
752 | return ret; |
753 | } |
754 | |
755 | static int adc_tm5_gen2_init(struct adc_tm5_chip *chip) |
756 | { |
757 | u8 channels_available; |
758 | int ret; |
759 | unsigned int i; |
760 | |
761 | ret = adc_tm5_read(adc_tm: chip, ADC_TM5_NUM_BTM, |
762 | data: &channels_available, len: sizeof(channels_available)); |
763 | if (ret) { |
764 | dev_err(chip->dev, "read failed for BTM channels\n" ); |
765 | return ret; |
766 | } |
767 | |
768 | for (i = 0; i < chip->nchannels; i++) { |
769 | if (chip->channels[i].channel >= channels_available) { |
770 | dev_err(chip->dev, "Invalid channel %d\n" , chip->channels[i].channel); |
771 | return -EINVAL; |
772 | } |
773 | } |
774 | |
775 | mutex_init(&chip->adc_mutex_lock); |
776 | |
777 | return ret; |
778 | } |
779 | |
780 | static int adc_tm5_get_dt_channel_data(struct adc_tm5_chip *adc_tm, |
781 | struct adc_tm5_channel *channel, |
782 | struct device_node *node) |
783 | { |
784 | const char *name = node->name; |
785 | u32 chan, value, adc_channel, varr[2]; |
786 | int ret; |
787 | struct device *dev = adc_tm->dev; |
788 | struct of_phandle_args args; |
789 | |
790 | ret = of_property_read_u32(np: node, propname: "reg" , out_value: &chan); |
791 | if (ret) { |
792 | dev_err(dev, "%s: invalid channel number %d\n" , name, ret); |
793 | return ret; |
794 | } |
795 | |
796 | if (chan >= ADC_TM5_NUM_CHANNELS) { |
797 | dev_err(dev, "%s: channel number too big: %d\n" , name, chan); |
798 | return -EINVAL; |
799 | } |
800 | |
801 | channel->channel = chan; |
802 | |
803 | /* |
804 | * We are tied to PMIC's ADC controller, which always use single |
805 | * argument for channel number. So don't bother parsing |
806 | * #io-channel-cells, just enforce cell_count = 1. |
807 | */ |
808 | ret = of_parse_phandle_with_fixed_args(np: node, list_name: "io-channels" , cell_count: 1, index: 0, out_args: &args); |
809 | if (ret < 0) { |
810 | dev_err(dev, "%s: error parsing ADC channel number %d: %d\n" , name, chan, ret); |
811 | return ret; |
812 | } |
813 | of_node_put(node: args.np); |
814 | |
815 | if (args.args_count != 1) { |
816 | dev_err(dev, "%s: invalid args count for ADC channel %d\n" , name, chan); |
817 | return -EINVAL; |
818 | } |
819 | |
820 | adc_channel = args.args[0]; |
821 | if (adc_tm->data->gen == ADC_TM5_GEN2) |
822 | adc_channel &= 0xff; |
823 | |
824 | if (adc_channel >= ADC5_MAX_CHANNEL) { |
825 | dev_err(dev, "%s: invalid ADC channel number %d\n" , name, chan); |
826 | return -EINVAL; |
827 | } |
828 | channel->adc_channel = args.args[0]; |
829 | |
830 | channel->iio = devm_fwnode_iio_channel_get_by_name(dev: adc_tm->dev, |
831 | of_fwnode_handle(node), NULL); |
832 | if (IS_ERR(ptr: channel->iio)) { |
833 | ret = PTR_ERR(ptr: channel->iio); |
834 | if (ret != -EPROBE_DEFER) |
835 | dev_err(dev, "%s: error getting channel: %d\n" , name, ret); |
836 | return ret; |
837 | } |
838 | |
839 | ret = of_property_read_u32_array(np: node, propname: "qcom,pre-scaling" , out_values: varr, sz: 2); |
840 | if (!ret) { |
841 | ret = qcom_adc5_prescaling_from_dt(num: varr[0], den: varr[1]); |
842 | if (ret < 0) { |
843 | dev_err(dev, "%s: invalid pre-scaling <%d %d>\n" , |
844 | name, varr[0], varr[1]); |
845 | return ret; |
846 | } |
847 | channel->prescale = ret; |
848 | } else { |
849 | /* 1:1 prescale is index 0 */ |
850 | channel->prescale = 0; |
851 | } |
852 | |
853 | ret = of_property_read_u32(np: node, propname: "qcom,hw-settle-time-us" , out_value: &value); |
854 | if (!ret) { |
855 | ret = qcom_adc5_hw_settle_time_from_dt(value, hw_settle: adc_tm->data->hw_settle); |
856 | if (ret < 0) { |
857 | dev_err(dev, "%s invalid hw-settle-time-us %d us\n" , |
858 | name, value); |
859 | return ret; |
860 | } |
861 | channel->hw_settle_time = ret; |
862 | } else { |
863 | channel->hw_settle_time = VADC_DEF_HW_SETTLE_TIME; |
864 | } |
865 | |
866 | if (of_property_read_bool(np: node, propname: "qcom,ratiometric" )) |
867 | channel->cal_method = ADC_TM5_RATIOMETRIC_CAL; |
868 | else |
869 | channel->cal_method = ADC_TM5_ABSOLUTE_CAL; |
870 | |
871 | if (adc_tm->data->gen == ADC_TM5_GEN2) { |
872 | ret = of_property_read_u32(np: node, propname: "qcom,decimation" , out_value: &value); |
873 | if (!ret) { |
874 | ret = qcom_adc5_decimation_from_dt(value, decimation: adc_tm->data->decimation); |
875 | if (ret < 0) { |
876 | dev_err(dev, "invalid decimation %d\n" , value); |
877 | return ret; |
878 | } |
879 | channel->decimation = ret; |
880 | } else { |
881 | channel->decimation = ADC5_DECIMATION_DEFAULT; |
882 | } |
883 | |
884 | ret = of_property_read_u32(np: node, propname: "qcom,avg-samples" , out_value: &value); |
885 | if (!ret) { |
886 | ret = qcom_adc5_avg_samples_from_dt(value); |
887 | if (ret < 0) { |
888 | dev_err(dev, "invalid avg-samples %d\n" , value); |
889 | return ret; |
890 | } |
891 | channel->avg_samples = ret; |
892 | } else { |
893 | channel->avg_samples = VADC_DEF_AVG_SAMPLES; |
894 | } |
895 | } |
896 | |
897 | return 0; |
898 | } |
899 | |
900 | static const struct adc_tm5_data adc_tm5_data_pmic = { |
901 | .full_scale_code_volt = 0x70e4, |
902 | .decimation = (unsigned int []) { 250, 420, 840 }, |
903 | .hw_settle = (unsigned int []) { 15, 100, 200, 300, 400, 500, 600, 700, |
904 | 1000, 2000, 4000, 8000, 16000, 32000, |
905 | 64000, 128000 }, |
906 | .disable_channel = adc_tm5_disable_channel, |
907 | .configure = adc_tm5_configure, |
908 | .isr = adc_tm5_isr, |
909 | .init = adc_tm5_init, |
910 | .irq_name = "pm-adc-tm5" , |
911 | .gen = ADC_TM5, |
912 | }; |
913 | |
914 | static const struct adc_tm5_data adc_tm_hc_data_pmic = { |
915 | .full_scale_code_volt = 0x70e4, |
916 | .decimation = (unsigned int []) { 256, 512, 1024 }, |
917 | .hw_settle = (unsigned int []) { 0, 100, 200, 300, 400, 500, 600, 700, |
918 | 1000, 2000, 4000, 6000, 8000, 10000 }, |
919 | .disable_channel = adc_tm5_disable_channel, |
920 | .configure = adc_tm5_configure, |
921 | .isr = adc_tm5_isr, |
922 | .init = adc_tm_hc_init, |
923 | .irq_name = "pm-adc-tm5" , |
924 | .gen = ADC_TM_HC, |
925 | }; |
926 | |
927 | static const struct adc_tm5_data adc_tm5_gen2_data_pmic = { |
928 | .full_scale_code_volt = 0x70e4, |
929 | .decimation = (unsigned int []) { 85, 340, 1360 }, |
930 | .hw_settle = (unsigned int []) { 15, 100, 200, 300, 400, 500, 600, 700, |
931 | 1000, 2000, 4000, 8000, 16000, 32000, |
932 | 64000, 128000 }, |
933 | .disable_channel = adc_tm5_gen2_disable_channel, |
934 | .configure = adc_tm5_gen2_configure, |
935 | .isr = adc_tm5_gen2_isr, |
936 | .init = adc_tm5_gen2_init, |
937 | .irq_name = "pm-adc-tm5-gen2" , |
938 | .gen = ADC_TM5_GEN2, |
939 | }; |
940 | |
941 | static int adc_tm5_get_dt_data(struct adc_tm5_chip *adc_tm, struct device_node *node) |
942 | { |
943 | struct adc_tm5_channel *channels; |
944 | struct device_node *child; |
945 | u32 value; |
946 | int ret; |
947 | struct device *dev = adc_tm->dev; |
948 | |
949 | adc_tm->nchannels = of_get_available_child_count(np: node); |
950 | if (!adc_tm->nchannels) |
951 | return -EINVAL; |
952 | |
953 | adc_tm->channels = devm_kcalloc(dev, n: adc_tm->nchannels, |
954 | size: sizeof(*adc_tm->channels), GFP_KERNEL); |
955 | if (!adc_tm->channels) |
956 | return -ENOMEM; |
957 | |
958 | channels = adc_tm->channels; |
959 | |
960 | adc_tm->data = of_device_get_match_data(dev); |
961 | if (!adc_tm->data) |
962 | adc_tm->data = &adc_tm5_data_pmic; |
963 | |
964 | ret = of_property_read_u32(np: node, propname: "qcom,decimation" , out_value: &value); |
965 | if (!ret) { |
966 | ret = qcom_adc5_decimation_from_dt(value, decimation: adc_tm->data->decimation); |
967 | if (ret < 0) { |
968 | dev_err(dev, "invalid decimation %d\n" , value); |
969 | return ret; |
970 | } |
971 | adc_tm->decimation = ret; |
972 | } else { |
973 | adc_tm->decimation = ADC5_DECIMATION_DEFAULT; |
974 | } |
975 | |
976 | ret = of_property_read_u32(np: node, propname: "qcom,avg-samples" , out_value: &value); |
977 | if (!ret) { |
978 | ret = qcom_adc5_avg_samples_from_dt(value); |
979 | if (ret < 0) { |
980 | dev_err(dev, "invalid avg-samples %d\n" , value); |
981 | return ret; |
982 | } |
983 | adc_tm->avg_samples = ret; |
984 | } else { |
985 | adc_tm->avg_samples = VADC_DEF_AVG_SAMPLES; |
986 | } |
987 | |
988 | for_each_available_child_of_node(node, child) { |
989 | ret = adc_tm5_get_dt_channel_data(adc_tm, channel: channels, node: child); |
990 | if (ret) { |
991 | of_node_put(node: child); |
992 | return ret; |
993 | } |
994 | |
995 | channels++; |
996 | } |
997 | |
998 | return 0; |
999 | } |
1000 | |
1001 | static int adc_tm5_probe(struct platform_device *pdev) |
1002 | { |
1003 | struct device_node *node = pdev->dev.of_node; |
1004 | struct device *dev = &pdev->dev; |
1005 | struct adc_tm5_chip *adc_tm; |
1006 | struct regmap *regmap; |
1007 | int ret, irq; |
1008 | u32 reg; |
1009 | |
1010 | regmap = dev_get_regmap(dev: dev->parent, NULL); |
1011 | if (!regmap) |
1012 | return -ENODEV; |
1013 | |
1014 | ret = of_property_read_u32(np: node, propname: "reg" , out_value: ®); |
1015 | if (ret) |
1016 | return ret; |
1017 | |
1018 | adc_tm = devm_kzalloc(dev: &pdev->dev, size: sizeof(*adc_tm), GFP_KERNEL); |
1019 | if (!adc_tm) |
1020 | return -ENOMEM; |
1021 | |
1022 | adc_tm->regmap = regmap; |
1023 | adc_tm->dev = dev; |
1024 | adc_tm->base = reg; |
1025 | |
1026 | irq = platform_get_irq(pdev, 0); |
1027 | if (irq < 0) |
1028 | return irq; |
1029 | |
1030 | ret = adc_tm5_get_dt_data(adc_tm, node); |
1031 | if (ret) |
1032 | return dev_err_probe(dev, err: ret, fmt: "get dt data failed\n" ); |
1033 | |
1034 | ret = adc_tm->data->init(adc_tm); |
1035 | if (ret) { |
1036 | dev_err(dev, "adc-tm init failed\n" ); |
1037 | return ret; |
1038 | } |
1039 | |
1040 | ret = adc_tm5_register_tzd(adc_tm); |
1041 | if (ret) { |
1042 | dev_err(dev, "tzd register failed\n" ); |
1043 | return ret; |
1044 | } |
1045 | |
1046 | return devm_request_threaded_irq(dev, irq, NULL, thread_fn: adc_tm->data->isr, |
1047 | IRQF_ONESHOT, devname: adc_tm->data->irq_name, dev_id: adc_tm); |
1048 | } |
1049 | |
1050 | static const struct of_device_id adc_tm5_match_table[] = { |
1051 | { |
1052 | .compatible = "qcom,spmi-adc-tm5" , |
1053 | .data = &adc_tm5_data_pmic, |
1054 | }, |
1055 | { |
1056 | .compatible = "qcom,spmi-adc-tm-hc" , |
1057 | .data = &adc_tm_hc_data_pmic, |
1058 | }, |
1059 | { |
1060 | .compatible = "qcom,spmi-adc-tm5-gen2" , |
1061 | .data = &adc_tm5_gen2_data_pmic, |
1062 | }, |
1063 | { } |
1064 | }; |
1065 | MODULE_DEVICE_TABLE(of, adc_tm5_match_table); |
1066 | |
1067 | static struct platform_driver adc_tm5_driver = { |
1068 | .driver = { |
1069 | .name = "qcom-spmi-adc-tm5" , |
1070 | .of_match_table = adc_tm5_match_table, |
1071 | }, |
1072 | .probe = adc_tm5_probe, |
1073 | }; |
1074 | module_platform_driver(adc_tm5_driver); |
1075 | |
1076 | MODULE_DESCRIPTION("SPMI PMIC Thermal Monitor ADC driver" ); |
1077 | MODULE_LICENSE("GPL v2" ); |
1078 | |